How to reuse one rule for multiple similar scenarios

I put together something that should kind of work. Here is what it does

a. It uses parent child structure so you can create child app for each room
b. Child apps use the following: a temp sensor for the room, a switch to turn on a heater, a offset so it will allow a variation of x degrees up and down. Last a toggle to set a setpoint, or use a thermostat for it, lastly based on what you select a entry for it
c. You would use a Virtual Thermostat per room and the Built-in thermostat scheduler to build out the schedule to set your schedule for personalized set points throughout the day or based on presence.

Does that sound like what you want. I can post it if you want it. I may continue to enhance this so it can work with Govee space heaters and my integration.

2 Likes

Damn, you people who can throw apps together like this impress me. And in addition that you're just being really nice, great contribution to the forum.

The thing is it really helps to already have the shell from a previous app. I litterly copied both the parent and child apps i mentioned earlier and then just changed descriptive stuff to make it make more sense for this ask. The actual logic is very simple and most of the code is just the UI.

As @ogiewon said once you get the basics down this kind of smart app is easy.

I will clean it up a bit and post it here.

1 Like

Iā€™m getting so much good advice on here that its hard to keep up with responding to everyone.

So, firstly, thanks all. Itā€™s given me a lot to think about and explore.

I would really like to see the example from @mavrrick58 Examples are good. I donā€™t believe in reinventing the wheel and some parent/child examples to start from would be ideal. Groovy doesn't look too different to a lot of other things (but I do wish I didn't have to keep learning a new, slightly different language so regularly. I'm sure the hubitat developers will have a good reason why, but... :upside_down_face:)

And, sorry @danabw I donā€™t think Iā€™ll be releasing anything of my own just yet. Iā€™ve still got a lot to learn!

1 Like

Here is the code. I tried to clean it up a bit this morning and make sure it was all working as expected. I haven't used it fully myself except for testing on my dev hub. That said i do believe the idea is fully functinoal. I will also put this under my github as well..

Here is the code

Parent app:

/**
 *  Heater control using an external temp sensor or weather underground
 *
 *  Copyright 2015 Mavrrick
 *
 *  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.
 *
 */
 /**
 * 10/31/2018
 * Updated required fields so the application can be used simply to humidify or dehumidify and not require both functions
 * Corrected value used for humidification low value to turn on assigned switch
 */
definition(
    name: "Heater Manager",
    namespace: "Mavrrick",
    author: "Mavrrick",
    description: "Manages Heat in home with Space Heaters",
    category: "Convenience",
    installOnOpen: "true",
    singleInstance: "true",
    iconUrl: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather2-icn",
    iconX2Url: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather2-icn?displaySize=2x"
)

preferences {
    page(name: "setupMain")
}

def setupMain() {
    dynamicPage(name: "setupMain", title: " ", install: true, uninstall: true) {
        section("Manage Heater ManagerInstances") {
            app(name: "Heat Manager", appName: "Heater Manager-Child", namespace: "Mavrrick", title: "Heater Manager Instance", multiple: true)
        } 
    }
}
        
def installed() {

}

def updated() {

}

Child App:

/**
 *  Heater control using an external temp sensor or weather underground
 *
 *  Copyright 2015 Mavrrick
 *
 *  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.
 *
 */
 /**
 * 10/31/2018
 * Updated required fields so the application can be used simply to humidify or dehumidify and not require both functions
 * Corrected value used for humidification low value to turn on assigned switch
 */
definition(
    name: "Heater Manager-Child",
    namespace: "Mavrrick",
    author: "Mavrrick",
    description: "Manages Heat in home using Space Heaters",
    category: "Convenience",
    parent: "Mavrrick:Heater Manager",
    iconUrl: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather2-icn",
    iconX2Url: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather2-icn?displaySize=2x"
)


preferences { 
    page(name: "page1", title: "Select sensors and set confortable humidity range", install: true, uninstall: true){ 
	 section("Give this app a name?") {
     label(name: "label",
     title: "Give this app a name?",
     required: false,
     multiple: false)
	}
	section("Room Temp Sensor:") {
	input ("tempInput", "capability.temperatureMeasurement", required: true)
	}   
    section("Space Heater?") {
		input ("switch2", "capability.switch", required: false)
	}
    section("Temp On/Off range") {
        input ("tempRange", "number", title: "Desired Temperature Variance for on/off range above and below the setpoint.  Default is 1%.", required: false)
    }
     section( "Setpoint set by:" ) {
        input ("setPointSupply", "enum", title: "which source?",
              options: ["Entry", "Thermostat"], required: true, submitOnChange: true)
    }
    
    if (setPointSupply == "Entry") {
	    section("Enter Setpoint") {
        input ("tempMin", "number", title: "Desired minimum temp.", required: false)
        }
}
	else {
    section("Which sensor will supply the temperature?") { 
    input ("thermostat", "capability.thermostat", required: false)
    }
 }
    		section(/*getFormat("header-green", "${getImage("Blank")}"+*/ " General") /*)*/ {
//            label title: "Enter a name for this automation", required: false
            input "logEnable", "bool", defaultValue: false, title: "Enable Debug Logging", description: "debugging"
		}
}
}
        
def installed() {
	subscribe(tempInput, "temperature", tempAction)
    log.info("Installed Heater manager application")
}

def updated() {
	unsubscribe()
	subscribe(tempInput, "temperature", tempAction)
    log.info("Updated Heater manager application")
}
     
     
def tempAction(evt) {
    if (logEnable) log.debug("tempAction(): Temp action to validate temp event ${evt.value}") 
    long evt2 = evt.value.toLong()
    if (setPointSupply == "Entry") {
        tempOn = (tempMin - tempRange)
        tempOff = (tempMin + tempRange)
    } else {
        if (logEnable) log.debug("tempAction(): Current thermostat set point is ${thermostat.currentValue("heatingSetpoint")}")
         setpoint = thermostat.currentValue("heatingSetpoint").toLong()
         tempOn = (setpoint - tempRange)
         tempOff = (setpoint + tempRange)
    }
    if (logEnable) log.debug("tempAction(): Temp to turn off at ${tempOff}, Temp to turn on at ${tempOn} based on variance ") 
    if (evt2 < tempOn && "off" == switch2.currentSwitch) {
        if (logEnable) log.debug("tempAction(): Temp below minimum = ${evt.value}. Turning On Heater") 
        switch2.on()
    }
    else if (evt2 > tempOff && "on" == switch2.currentSwitch) {
        if (logEnable) log.debug("tempAction(): Temp above setpoint = ${evt.value}. Turning off Heater")
        switch2.off()
    }
    else  {
    if (logEnable) log.debug("tempAction(): no change = ${evt.value}")
    }
}

The parent app is pretty typical for this type of thing. It just calls out that it is a parent and then what it's child name space and such is to call when it goes to set it up. You an put multiple entries in there if you had different kinds of child apps.

The child app is just as the inputs i mentioned above. Then it just has a simple bit of logic that based on how you setup your set point. it will turn on/off the heater device based on either a set temp value or based on a external Thermostat.

The logic is pretty simple: On any temp change for your triggering temp sensnr it collects and calculates your temp on/off values based on your set point source and the variance values. Then If it is below the set point value - variance and the device is turned off, it turns on the heater. If it is above the setpoint+variance value and the heater is on, it turns off the heater. If neither of those conditions are correct it just ignores the change and doesn't do anything.

For dynamic set points by room you will want to use the set point source as a thermostat. This means you will need to setup a virtual thermostat for the room before hand. To make it dynamic you will want to use the built in Thermostat Scheduler app. You may need to adjust this by season yourself though or create multiple instances that you disable enable by season.

1 Like

Thanks.