Hvac zoning app

can you all help get the code done?
ventStatus will not change to Close if desired temperature reached for a Vent.

ecobee Suite Smart Vents` automates one or more vents to reach/maintain a target temperature that you specify or from a specified thermostat. It uses one or more temperature devices, and opens/closes vents based upon current temperature, target temperature and thermostat operating state. this what I'm look to do with the.

definition(
    name: "Ecobee Smart Vent Controller",
    namespace: "yourNamespace",
    author: "yourName",
    description: "Control Ecobee Smart Vents based on temperature readings for multiple rooms.",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: ""
)

preferences {
    (1..20).each { roomNum ->
        section("Room ${roomNum} Setup:") {
            input "room${roomNum}Sensor", "capability.temperatureMeasurement", title: "Room ${roomNum} Temperature Sensor", required: false
            input "room${roomNum}Vents", "capability.switch", title: "Room ${roomNum} Ecobee Smart Vents", multiple: true, required: false
            input "room${roomNum}TargetTemp", "number", title: "Room ${roomNum} Target Temperature (°F)", required: false
        }
    }
}

def installed() {
    subscribeToTemperatureSensors()
    log.info "Ecobee Smart Vent Controller installed"
}

def updated() {
    unsubscribe()
    subscribeToTemperatureSensors()
    log.info "Ecobee Smart Vent Controller updated"
}

def subscribeToTemperatureSensors() {
    (1..20).each { roomNum ->
        def sensor = settings["room${roomNum}Sensor"]
        if (sensor) {
            subscribe(sensor, "temperature", "room${roomNum}TemperatureHandler")
        }
    }
}

(1..20).each { roomNum ->
    // Dynamic method generation for room temperature handlers
    def methodName = "room${roomNum}TemperatureHandler"
    this."$methodName" = { evt -> 
        handleRoomTemperature(evt, roomNum) 
    }
}

def handleRoomTemperature(evt, roomNum) {
    def currentTemp = evt.doubleValue
    def targetTemp = settings["room${roomNum}TargetTemp"]
    log.info "Room ${roomNum}: Current temperature is ${currentTemp}°F, Target temperature is ${targetTemp}°F"

    if (currentTemp < targetTemp) {
        openRoomVents(roomNum)
    } else {
        closeRoomVents(roomNum)
    }
}

def openRoomVents(roomNum) {
    def vents = settings["room${roomNum}Vents"]
    if (vents) {
        vents.each { vent ->
            if (vent.currentSwitch == "off") {
                vent.on()
                log.info "${vent.displayName} opened in Room ${roomNum}"
            }
        }
    }
}

def closeRoomVents(roomNum) {
    def vents = settings["room${roomNum}Vents"]
    if (vents) {
        vents.each { vent ->
            if (vent.currentSwitch == "on") {
                vent.off()
                log.info "${vent.displayName} closed in Room ${roomNum}"
            }
        }
    }
}

that is code I have so far using chatgpt.com

What vents do you have? @storageanarchy's Ecobee Suite comes with a helper app for Keen Smart Vents.

1 Like

In have it install but can not figure out how to setup room by room zoning?

If bad room 75 then open the Vent until the tamp it 69 then close then Vent.

I had the EcobeeSetZoneWithSchedule code at one time.

I just moved and all my 3D printers are down right now can someone print and design me a 4x4 register and assemble it and mail it to me.? What would the cost be?

new cod

definition(
    name: "HVAC Zoning - Parent",
    namespace: "example",
    author: "ChatGPT",
    description: "Parent app for HVAC zoning with polling and back-pressure logic",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: ""
)

preferences {
    page(name: "mainPage", title: "HVAC Zoning Parent Settings", install: true, uninstall: true) {
        section("Global Settings") {
            input "pollInterval", "number", title: "Check interval (minutes)", required: true, defaultValue: 5, range: "1..60"
            input "minimumOpenVents", "number", title: "Minimum number of vents to stay open", required: true, defaultValue: 1
        }
        section("Zones") {
            app(name: "zones", appName: "Simple HVAC Zoning - Child", namespace: "example", title: "Add a Zone", multiple: true)
        }
    }
}

def installed() {
    initialize()
}

def updated() {
    unschedule()
    initialize()
}

def initialize() {
    schedule("0 */${pollInterval} * * * ?", pollZones)
    pollZones() // Run immediately
}

def pollZones() {
    log.debug "Polling all child zones..."
    childApps.each { it.checkZone() }
}

def countOpenVents() {
    def count = childApps.count { it.isVentOpen() }
    log.debug "Currently ${count} vent(s) open"
    return count
}
definition(
    name: "HVAC Zoning - Child",
    namespace: "example",
    author: "ChatGPT",
    description: "Child app for HVAC zone with setpoint and numeric level vent control (0/100)",
    category: "Convenience",
    parent: "example:HVAC Zoning - Parent",
    iconUrl: "",
    iconX2Url: ""
)

preferences {
    page(name: "zonePage", title: "Configure Zone", install: true, uninstall: true) {
        section("Zone Settings") {
            input "roomName", "text", title: "Room Name", required: true
            input "tempSensor", "capability.temperatureMeasurement", title: "Temperature Sensor", required: true
            input "ventSwitch", "capability.switchLevel", title: "Vent Actuator (0 = Closed, 100 = Open)", required: true
            input "zoneSetpoint", "decimal", title: "Room Setpoint Temperature (°F)", required: true, defaultValue: 72.0
        }
    }
}

def installed() {
    updateAppLabel()
}

def updated() {
    updateAppLabel()
}

def updateAppLabel() {
    if (roomName && app.label != roomName) {
        app.updateLabel(roomName)
        log.info "App label set to '${roomName}'"
    }
}

def isVentOpen() {
    return (ventSwitch.currentValue("level") as Integer) > 0
}

def checkZone() {
    def currentTemp = tempSensor?.currentTemperature
    if (currentTemp == null) {
        log.warn "No temperature reported for sensor in ${roomName}"
        return
    }

    def parentMinimum = parent.minimumOpenVents ?: 1
    def openCount = parent.countOpenVents()
    def currentLevel = ventSwitch.currentValue("level") as Integer

    log.debug "Room: ${roomName} | Temp: ${currentTemp}°F | Setpoint: ${zoneSetpoint}°F | Vent Level: ${currentLevel} | Open Vents: ${openCount}"

    if (currentTemp < zoneSetpoint) {
        // Open vent to 100%
        if (currentLevel < 100) {
            ventSwitch.setLevel(100)
            log.info "Opening vent in ${roomName} to 100% (temp ${currentTemp} < setpoint ${zoneSetpoint})"
        }
    } else {
        // Close vent to 0%, only if enough others are open
        if (currentLevel > 0) {
            if (openCount > parentMinimum) {
                ventSwitch.setLevel(0)
                log.info "Closing vent in ${roomName} (temp ${currentTemp} ≥ setpoint ${zoneSetpoint})"
            } else {
                log.warn "Vent in ${roomName} should close, but kept open to avoid back pressure (only ${openCount} vents open)"
            }
        }
    }
}

Can you all test for me I do not have my vent's setup right now.

It’s hard to understand what you are trying to do that cannot be done with @storageanarchy’s Ecobee Suite.

Does that app suite lack a feature you’re trying to implement? Or were you unable to configure it properly to achieve your goal?

Also if you used ChatGPT to create the code in this thread, there’s a good chance it stole from someone else’s code without attribution (like @storageanarchy, for example).

If that’s actually the case, you should avoid sharing the code with others, or at least attribute the actual developer(s) of the code that ChatGPT used.

2 Likes

I can not get Ecobee Suite setup to us temp and vents

If I were you, I’d try to use the code that was created by a knowledgeable/experienced human before moving on to asking an LLM to create new code for me (I don’t know anything about coding either).

The thread that @aaiyar linked to is the best place to ask for help.

Also how are you planning to do any of this if you don’t have any smart vents currently installed in your new home?

1 Like

I'm waiting on https://github.com/BrobstonCreations/yet-another-smart-vent a 12x12 vent and a 10x10 vent to 3d print. I have the Keen vents that I can test with.
but if the batter were left in the it will not work.

new code add ac thermostat control

definition(
    name: "HVAC Zoning - Parent",
    namespace: "example",
    author: "Your Name",
    description: "HVAC zoning with thermostat control",
    category: "Convenience",
    iconUrl: "https://raw.githubusercontent.com/hubitat/example-icons/main/hvac.png",
    iconX2Url: "https://raw.githubusercontent.com/hubitat/example-icons/main/hvac@2x.png"
)

preferences {
    section("Select Thermostat Device:") {
        input "thermostat", "capability.thermostat", title: "Thermostat Device", required: true
    }
    section("Child Zones") {
        app(name: "childZones", appName: "HVAC Zoning - Child", namespace: "example", title: "Add HVAC Zone", multiple: true)
    }
}

def installed() {
    initialize()
}

def updated() {
    initialize()
}

def initialize() {
    state.roomsStatus = [:]
}

def reportRoomStatus(String roomName, Boolean atSetpoint, Double roomSetPoint = null) {
    if (state.roomsStatus == null) {
        state.roomsStatus = [:]
    }
    state.roomsStatus[roomName] = [atSetpoint: atSetpoint, setPoint: roomSetPoint]
    log.debug "Room '${roomName}' at setpoint? ${atSetpoint}"
    updateThermostat()
}

def updateThermostat() {
    def roomsStatus = state.roomsStatus ?: [:]
    def anyRoomNeedsCooling = roomsStatus.values().any { !it.atSetpoint }

    if (anyRoomNeedsCooling) {
        if (thermostat.currentThermostatMode != "cool") {
            thermostat.cool()
            log.debug "Thermostat set to COOL mode"
        }
        // Get minimum setpoint among rooms needing cooling
        def minSetpoint = roomsStatus.findAll { !it.value.atSetpoint }
                                    .collect { it.value.setPoint ?: 75 }
                                    .min()
        if (minSetpoint) {
            thermostat.setCoolingSetpoint(minSetpoint)
            log.debug "Cooling setpoint set to ${minSetpoint}"
        }
    } else {
        if (thermostat.currentThermostatMode != "off") {
            thermostat.off()
            log.debug "Thermostat turned OFF — all rooms at setpoint"
        }
    }
}
definition(
    name: "HVAC Zoning - Child",
    namespace: "example",
    author: "Your Name",
    description: "Single HVAC Zone",
    category: "Convenience",
    iconUrl: "https://raw.githubusercontent.com/hubitat/example-icons/main/vent.png",
    iconX2Url: "https://raw.githubusercontent.com/hubitat/example-icons/main/vent@2x.png"
)

preferences {
    section("Room Details") {
        input "roomName", "text", title: "Room Name", required: true
        input "setPoint", "decimal", title: "Temperature Set Point", required: true
    }
    section("Devices") {
        input "tempSensor", "capability.temperatureMeasurement", title: "Temperature Sensor", required: true
        input "vent", "capability.switchLevel", title: "Vent (Dimmer Switch)", required: true
    }
}

def installed() {
    initialize()
}

def updated() {
    initialize()
}

def initialize() {
    runEvery5Minutes("checkTemperature")
    checkTemperature()
}

def checkTemperature() {
    def currentTemp = tempSensor.currentTemperature as Double
    def targetTemp = setPoint as Double
    def ventLevel = vent.currentLevel as Integer ?: 0

    if (currentTemp >= targetTemp) {
        // Temp above or at set point: Open vent fully
        if (ventLevel != 100) {
            vent.setLevel(100)
            log.debug "$roomName: Temp $currentTemp >= setpoint $targetTemp, opening vent"
        }
        parent.reportRoomStatus(roomName, true, targetTemp)
    } else {
        // Temp below set point: Close vent
        if (ventLevel != 0) {
            vent.setLevel(0)
            log.debug "$roomName: Temp $currentTemp < setpoint $targetTemp, closing vent"
        }
        parent.reportRoomStatus(roomName, false, targetTemp)
    }
}

:point_up:

1 Like