Couldn't find it either so I had AI generate it 
AI Generated API Endpoint Documentation
The ClimateMaster CM300 smart thermostat (models AVB32V02C / AVB32V02R) features a built-in Local API that allows third-party smart home hubs and software to monitor and control the system locally. The CM300 hardware and firmware run on an OEM platform identical to the well-documented Venstar Local API.[1, 2, 3]
To use these endpoints, you must first enable the Local API on the thermostat hardware (Menu > Settings > Installation Settings > Skyport > API > ON). [1]
ClimateMaster CM300 Local API Documentation
Base Configuration & Authentication
- Protocol: HTTP
- Base URL:
http://<thermostat_ip_address>/
- Authentication: None (when configured for basic local access) or HTTP Digest Authentication if a password is set via the ClimateMaster Configurator App.
- Data Format: Content-Type
application/x-www-form-urlencoded (POST) / application/json(Response). [1]
- GET Endpoints (Monitoring & Status)
GET /
Verifies the local API connection and identifies the device platform.
json
{
"api_version": 6,
"type": "thermostat"
}
Use code with caution.
[1]
GET /query/info
Retrieves the comprehensive operational state of the thermostat, current climate metrics, and HVAC system relays. [1]
- Response Fields:
name: Assigned string name of the thermostat.
mode: Current operating mode (0: OFF, 1: HEAT, 2: COOL, 3: AUTO, 4: EM HEAT).
state: Relay active state (0: Idle, 1: Heating, 2: Cooling).
fan: Fan operational state (0: AUTO, 1: ON).
fanstate: Physical fan relay state (0: Off, 1: Running).
tempunits: Scale metric (0: Fahrenheit, 1: Celsius).
schedule: Program routine status (0: Disabled, 1: Enabled).
schedulepart: Current active routine step (0 to 3 for parts 1–4).
away: Energy-saving away status (0: Home, 1: Away).
spacetemp: Live room temperature reading.
heattemp: Active target heating setpoint.
cooltemp: Active target cooling setpoint.
hum: Internal relative humidity percentage. [1, 2, 3, 4, 5]
GET /query/sensors
Queries all onboard, wired, and accessory climate probe points. [1]
- Response Fields:
sensors: Array containing objects with name, type ("indoor", "outdoor", "remote"), and temp values.[1, 2, 3, 4, 5]
- POST Endpoints (Control & Configuration)
POST /control
Modifies primary temperature thresholds, equipment operational modes, and fan status. [1]
| Parameter [1, 2, 3, 4] |
Type |
Valid Values |
Description |
mode |
Integer |
0, 1, 2, 3, 4 |
0=OFF, 1=HEAT, 2=COOL, 3=AUTO, 4=EM HEAT |
fan |
Integer |
0, 1 |
0=AUTO, 1=ON |
heattemp |
Float |
50 to 88 |
Target heating temperature boundary in configured units |
cooltemp |
Float |
52 to 90 |
Target cooling temperature boundary in configured units |
- Example Request Payload:
mode=3&fan=0&heattemp=68&cooltemp=74
- Success Response:
{"success": true}
POST /settings
Overrides systemic structural states like schedule behaviors or vacation modes. [1, 2]
| Parameter [1, 2] |
Type |
Valid Values |
Description |
schedule |
Integer |
0, 1 |
0=Follow no schedule, 1=Activate onboard 7-day program |
away |
Integer |
0, 1 |
0=Home profile metrics, 1=Force system into away targets |
- Example Request Payload:
schedule=0&away=1
- Success Response:
{"success": true}
AI Generated Driver (not tested)
/**
* ClimateMaster CM300 Local LAN Driver
* Source Compatibility: Venstar Local API Spec
*/
metadata {
definition (
name: "ClimateMaster CM300 Thermostat",
namespace: "custom.climatemaster",
author: "SmartHome Community"
) {
capability "Thermostat"
capability "Refresh"
capability "Configuration"
attribute "fanstate", "number"
attribute "equipmentState", "string"
}
preferences {
input name: "deviceIP", type: "text", title: "Thermostat IP Address", description: "e.g. 192.168.1.50", required: true
input name: "refreshInterval", type: "enum", title: "Polling Interval", options: ["1":"1 Minute", "5":"5 Minutes", "10":"10 Minutes"], defaultValue: "5", required: true
}
}
// Automatically runs on saving preferences
def updated() {
log.info "ClimateMaster CM300 updating settings..."
unschedule()
def interval = settings.refreshInterval ? settings.refreshInterval.toInteger() : 5
schedule("0 */${interval} * ? * *", refresh)
refresh()
}
def configure() {
updated()
}
// Core retrieval logic via GET method
def refresh() {
if (!settings.deviceIP) {
log.warn "Device IP not configured on ClimateMaster CM300"
return
}
def params = [
uri: "http://${settings.deviceIP}/control/query/info",
timeout: 10
]
asynchttpGet("parseQueryResponse", params)
}
// Callback handler verifying and parsing payload properties
def parseQueryResponse(response, data) {
if (response.hasError() || response.status != 200) {
log.error "Failed to pull statistics from ClimateMaster API: ${response.errorMessage}"
return
}
try {
def json = parseJson(response.data)
// Temperature Mapping
def unit = (json.tempunits == 1) ? "C" : "F"
sendEvent(name: "temperature", value: json.space_temp, unit: unit)
sendEvent(name: "heatingSetpoint", value: json.heattemp, unit: unit)
sendEvent(name: "coolingSetpoint", value: json.cooltemp, unit: unit)
// Mode Conversions
def modeMap = [0:"off", 1:"heat", 2:"cool", 3:"auto"]
sendEvent(name: "thermostatMode", value: modeMap[json.mode.toInteger()])
// Fan Conversions
def fanMap = [0:"auto", 1:"on"]
sendEvent(name: "thermostatFanMode", value: fanMap[json.fan.toInteger()])
sendEvent(name: "fanstate", value: json.fanstate)
// Operating State Calculations
def stateMap = [0:"idle", 1:"heating", 2:"cooling"]
sendEvent(name: "thermostatOperatingState", value: stateMap[json.state.toInteger()])
log.debug "ClimateMaster state synchronized successfully."
} catch (Exception e) {
log.error "Exception occurred parsing driver response JSON: ${e.message}"
}
}
// Master HTTP POST execution layout
private void sendControlCommand(Map fieldPayload) {
if (!settings.deviceIP) return
def bodyText = fieldPayload.collect { k, v -> "${k}=${v}" }.join("&")
def params = [
uri: "http://${settings.deviceIP}/control",
body: bodyText,
requestContentType: "application/x-www-form-urlencoded",
timeout: 10
]
asynchttpPost("parseControlResponse", params)
}
def parseControlResponse(response, data) {
if (response.status == 200) {
// Force refresh to visually confirm hardware mutation states immediately
runIn(2, refresh)
} else {
log.error "Control endpoint rejected parameters payload: ${response.status}"
}
}
// Capability Command Overrides
def setHeatingSetpoint(temperature) {
sendControlCommand([heattemp: temperature])
}
def setCoolingSetpoint(temperature) {
sendControlCommand([cooltemp: temperature])
}
def setThermostatMode(String mode) {
def modeMap = ["off":0, "heat":1, "cool":2, "auto":3]
if (modeMap.containsKey(mode)) {
sendControlCommand([mode: modeMap[mode]])
}
}
def setThermostatFanMode(String fanMode) {
def fanMap = ["auto":0, "on":1]
if (fanMap.containsKey(fanMode)) {
sendControlCommand([fan: fanMap[fanMode]])
}
}
def off() { setThermostatMode("off") }
def heat() { setThermostatMode("heat") }
def cool() { setThermostatMode("cool") }
def auto() { setThermostatMode("auto") }
def fanAuto() { setThermostatFanMode("auto") }
def fanOn() { setThermostatFanMode("on") }