Hi Tony, I did used AI to write several Hubitat codes - including one for Hubitat integration with Airzone Local API. Here's mine, you can just copy paste from below
metadata {
definition(name: "Airzone Aidoo Pro (Local API)", namespace: "my hubitat", author: "AP'") {
capability "TemperatureMeasurement"
capability "RelativeHumidityMeasurement"
capability "Thermostat"
capability "Refresh"
capability "Polling"
attribute "connectivity", "string"
attribute "ecoMode", "string"
attribute "ecoCoolPoint", "number"
attribute "ecoHeatPoint", "number"
attribute "roomTemp", "number"
attribute "zoneID", "number"
attribute "systemID", "number"
attribute "modeText", "string"
attribute "fanModeText", "string"
attribute "supportedThermostatModes", "JSON_OBJECT"
attribute "supportedThermostatFanModes", "JSON_OBJECT"
command "setThermostatMode", [[name:"Thermostat mode*", type:"ENUM", constraints:["off","heat","cool","auto"]]]
command "setThermostatFanMode", [[name:"Fan mode*", type:"ENUM", constraints:["auto","on"]]]
command "setHeatingSetpoint", [[name:"Heating setpoint*", type:"NUMBER", description:"Set Heating Point (°C)"]]
command "setCoolingSetpoint", [[name:"Cooling setpoint*", type:"NUMBER", description:"Set Cooling Point (°C)"]]
command "refresh"
}
preferences {
input("ip", "string", title:"Aidoo IP Address", description:"Device local IP, e.g. 192.168.1.73", required: true)
input("systemID", "number", title:"System ID", description:"Usually 1", defaultValue:1, required: true)
input("zoneID", "number", title:"Zone ID", description:"Usually 1", defaultValue:1, required: true)
input("pollInterval", "number", title:"Polling interval (mins)", defaultValue:2, required: false)
}
}
def installed() { initialize() }
def updated() { unschedule(); initialize() }
def initialize() {
state.lastPoll = now()
if (settings.pollInterval) runEveryNMinutes("refresh", settings.pollInterval as int)
refresh()
}
// Main polling function - pulls latest zone/system state
def refresh() {
def apiUrl = "http://${settings.ip}:3000/api/v1/hvac"
def body = [systemID: settings.systemID, zoneID: settings.zoneID]
def params = [
uri: apiUrl,
contentType: "application/json",
body: groovy.json.JsonOutput.toJson(body),
timeout: 5
]
try {
httpPost(params) { resp ->
if(resp.status == 200 && resp.data?.data) {
parseApiResponse(resp.data.data[0])
sendEvent(name: "connectivity", value: "ONLINE")
} else {
sendEvent(name: "connectivity", value: "OFFLINE")
}
}
} catch (e) {
log.warn "Airzone API error: $e"
sendEvent(name: "connectivity", value: "OFFLINE")
}
}
def parseApiResponse(data) {
// Standard states
sendEvent(name: "temperature", value: data.roomTemp ?: data.setpoint)
sendEvent(name: "humidity", value: data.humidity ?: 0)
sendEvent(name: "heatingSetpoint", value: data.heatsetpoint ?: 0)
sendEvent(name: "coolingSetpoint", value: data.coolsetpoint ?: 0)
sendEvent(name: "thermostatMode", value: modeMap(data.mode))
sendEvent(name: "thermostatOperatingState", value: data.on ? "heating" : "idle")
sendEvent(name: "thermostatFanMode", value: fanModeMap(data.speed))
// Update available modes for drop-downs (always in sync)
sendEvent(name: "supportedThermostatModes", value: groovy.json.JsonOutput.toJson(["off","heat","cool","auto"]))
sendEvent(name: "supportedThermostatFanModes", value: groovy.json.JsonOutput.toJson(["auto","on"]))
// Custom states
sendEvent(name: "ecoMode", value: data.eco_mode ? "ON" : "OFF")
sendEvent(name: "ecoCoolPoint", value: data.ecoCoolPoint)
sendEvent(name: "ecoHeatPoint", value: data.ecoHeatPoint)
sendEvent(name: "roomTemp", value: data.roomTemp)
sendEvent(name: "zoneID", value: data.zoneID)
sendEvent(name: "systemID", value: data.systemID)
sendEvent(name: "modeText", value: modeMap(data.mode))
sendEvent(name: "fanModeText", value: fanModeMap(data.speed))
}
def modeMap(n) {
switch(n as int) {
case 1: return "heat"
case 2: return "cool"
case 3: return "auto"
case 4: return "off"
default: return "off"
}
}
def fanModeMap(n) {
switch(n as int) {
case 0: return "auto"
case 1: return "on"
default: return "auto"
}
}
// Set Thermostat Mode
def setThermostatMode(String mode) {
def modeVal = modeStrToApi(mode)
sendEvent(name: "thermostatMode", value: mode) // <-- UI stays in sync immediately
sendPut([systemID: settings.systemID, zoneID: settings.zoneID, mode: modeVal])
}
def setThermostatFanMode(String fanMode) {
def speedVal = (fanMode == "on") ? 1 : 0
sendEvent(name: "thermostatFanMode", value: fanMode)
sendPut([systemID: settings.systemID, zoneID: settings.zoneID, speed: speedVal])
}
def setHeatingSetpoint(setpoint) {
sendPut([systemID: settings.systemID, zoneID: settings.zoneID, heatsetpoint: setpoint as int])
}
def setCoolingSetpoint(setpoint) {
sendPut([systemID: settings.systemID, zoneID: settings.zoneID, coolsetpoint: setpoint as int])
}
def sendPut(bodyMap) {
def apiUrl = "http://${settings.ip}:3000/api/v1/hvac"
def params = [
uri: apiUrl,
contentType: "application/json",
body: groovy.json.JsonOutput.toJson(bodyMap),
timeout: 5
]
try {
httpPut(params) { resp ->
if(resp.status == 200) {
log.info "Set succeeded: ${resp.data}"
refresh()
} else {
log.warn "Set failed: ${resp.data}"
}
}
} catch (e) {
log.warn "Put error: $e"
}
}
def modeStrToApi(mode) {
switch(mode) {
case "heat": return 1
case "cool": return 2
case "auto": return 3
case "off": return 0
default: return 0
}
}