ChatGPT and I did an app, but we kindly need to ask for some assistance :)

Hi Guys,

I am trying to learn Groovy to make an app to control my air-to-air heat pump. I am struggling a bit so I asked ChatGPTs new code version for some assistance, and together we did an app that Hubitat accepted and saved. There is however a tiny flaw. Nothing happens. :smile:

If the inside temperature, provided buy a device, is below a certain temperature set by a user variable, the heat pump should start in heat mode and provide heat. If the inside temperature is over a certain temperature, again set using a variable, the heatpump should start in cooling mode and provide cooling air until a threshold temperature is reached, also set via a user variable.

Looking in the logfile it seems the app is picking up the temperature from the temperature device correctly. It also seems to only send one of three commands. I am guessing the syntax is incorrect for sending commands to the RM4 Pro? I can do this using Rule Machine so it is possible to do, but not this way it seems.

All suggestions on why nothing is happening are very welcome and much apreciated!

Log file:

App code:

definition(
    name: "Heat Pump Manager 0.2",
    namespace: "magnus_s",
    author: "magnus_s and ChatGPT",
    description: "Manage an air-to-air heat pump based on inside temperature.",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: ""
)

preferences {
    section("Select Devices") {
        input "tempDevice", "capability.temperatureMeasurement", title: "Select 'Termometer virtuell - Genomsnittstemperaturer - inomhus 3'", required: true, multiple: false
        input "broadlinkDevice", "capability.temperatureMeasurement", title: "Select 'Broadlink Remote 2023 01'", required: true, multiple: false
    }
    section("Temperature Settings") {
        input "heatPumpStartHeatTemp", "decimal", title: "Heat Pump Start Heat Temperature (°C)", required: true, defaultValue: 20.0
        input "heatPumpStartCoolTemp", "decimal", title: "Heat Pump Start Cool Temperature (°C)", required: true, defaultValue: 24.0
        input "heatPumpStopCoolTemp", "decimal", title: "Heat Pump Stop Cool Temperature (°C)", required: true, defaultValue: 22.0
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def initialize() {
    log.debug "Initializing"
    subscribe(tempDevice, "temperature", temperatureHandler)
}

def temperatureHandler(evt) {
    log.debug "Temperature event received: ${evt.value} from ${evt.device}"
    BigDecimal currentInsideTempV = evt.value.toBigDecimal()
    log.debug "Current inside temperature: ${currentInsideTempV}"
    manageHeatPump(currentInsideTempV)
}

def manageHeatPump(BigDecimal currentInsideTempV) {
    BigDecimal heatPumpStartHeatTempV = settings.heatPumpStartHeatTemp?.toBigDecimal() ?: 20.0
    BigDecimal heatPumpStartCoolTempV = settings.heatPumpStartCoolTemp?.toBigDecimal() ?: 24.0
    BigDecimal heatPumpStopCoolTempV = settings.heatPumpStopCoolTemp?.toBigDecimal() ?: 22.0

    if (currentInsideTempV < heatPumpStartHeatTempV) {
        log.debug "Current temperature (${currentInsideTempV}) is below heat threshold (${heatPumpStartHeatTempV}). Starting heat pump."
        sendBroadlinkCommands(["ON", "MODE_HEAT", "TEMP_24"])
    } else if (currentInsideTempV > heatPumpStartCoolTempV) {
        log.debug "Current temperature (${currentInsideTempV}) is above cool threshold (${heatPumpStartCoolTempV}). Starting cooling."
        sendBroadlinkCommands(["ON", "MODE_COLD", "TEMP_17"])
    } else if (currentInsideTempV < heatPumpStopCoolTempV && currentInsideTempV > heatPumpStartHeatTempV) {
        log.debug "Current temperature (${currentInsideTempV}) is within range. Stopping heat pump."
        sendBroadlinkCommand("OFF")
    }
}

def sendBroadlinkCommands(commands) {
    commands.eachWithIndex { cmd, idx ->
        runIn(idx * 2, sendBroadlinkCommand, [data: cmd])
    }
}

def sendBroadlinkCommand(cmd) {
    log.debug "Sending command to Broadlink: ${cmd}"
    broadlinkDevice.SendStoredCode(cmd)
}

EDIT: I was actually wrong, one command is sent by the RM4 Pro, I just didn't notice it. But only one is sent.

This is what the bit of the rule that caters for sending the commands in Rule Machine looks like (The rule is longer but essentially caters for different condintions when to send different values in the below format).

I think it would be useful to see the working RM rule, mainly just to see how the commands are being sent in RM where it does work. I am not familiar with the RM4 device.

1 Like

You have a bug in your runIn - you need to set overwrite: false in the options map if you want to queue up multiple scheduled instances of the same command in a loop.

Without that, I'm guessing that only the last command in the list runs each time.

3 Likes

Thanks for your reply Jeff. I updated the original post with an EDIT including information about the rule machine rule.

I think based on that, the bug @tomw has noticed may actually fix it for the most part.

So your runIn line would become this

runIn(idx * 2, sendBroadlinkCommand, [data: cmd, overwrite: false])

With that set it should run "ON" right away then "MODE_HEAT" in 2 seconds and "TEMP_24" in 4 seconds.

1 Like

Hi Tom, Thanks for your reply. You are right in that only one, the last, command is sent. Thanks for your suggestion.

Thanks for the link to the documentation as well. I am reading that too. A lot of documentation is sort of reference manual like giving facts about properties of things, but less of examples and creative suggestions. So I am feeling my way forward using several methods. Getting a nudge in the right direction is sometimes very helpful. Again, thanks for doing just that.

1 Like

Many thanks Jeff! Much appreciated. I'll incorparate this into the code continue to feel my way forward with this my first app. :slight_smile: :+1:

As a next suggestion, you may want to incorporate some logic to only send the command if its value has changed from the previous run.

As it is written now, you are guaranteed to send a command every time the temperature device reports a change in temperature. A large number of those will probably be redundant.

For example, you probably didn't need to send OFF if the prior command you sent was OFF.

1 Like

Thanks for the suggestion Tom! The heat pump sends a little beep confirming each command it recievs so that is a very good idea! :smile: So far I have been using a rule machine rule I created to mange the heat pump, a roof fan, some radiators and three under floor thermostats that together manage the heating and cooling of my house. I added the functionality you suggested pretty quickly to the rule machine rule :slight_smile: . I did that by introducing scenarios and keeping track of which scenario was active at the time. I am sure there are better ways to do that but it has worked so far.

The rule machine works great but has become so large it is no longer viable to maintain or develop, hence the plunge into the Groovy world. My house is not a model for excellent insulation so I have also incorprated some rules depending on the outside weather. I also use a dashboard for convinience to have the oportunity to change the temperature and global variables to let the rule know if I change anything using the dashboard so that it won't override. The plan is to incoproate all of this into the app. But I need to start slowly with some basics and take it set by step. I know I will hit a snag soon enough again and come back with more noob questions :slight_smile: and in time I can hopefully return some favours to the community. In the meantime, all suggestions are always appreciated and welcome, so thanks again.

1 Like