sburke781 / hubitat

Hubitat apps and device drivers
8 stars 8 forks source link

kumo cloud US min/max temp fields prevent setting correct temps in F #76

Open Lcstyle opened 2 years ago

Lcstyle commented 2 years ago

Can't set correct temps in F

Current States
    CanCool : true
    CanDry : true
    CanHeat : true
    HasAutomaticFanSpeed : false
    MaxTempAuto : 32
    MaxTempCool : 32
    MaxTempDry : 32
    MaxTempHeat : 32
    MinTempAuto : 32
    MinTempCool : 32
    MinTempDry : 32
    MinTempHeat : 32
    NumberOfFanSpeeds : 5
    coolingSetpoint : 72.0
    heatingSetpoint : 87.8
    lastCommandUTC : 2022-11-24 15:39:32.979Z
    lastRunningMode : heat
    speed : auto
    supportedThermostatFanModes : ["Off", "1", "2", "3", "4", "5", "On"]
    supportedThermostatModes : ["heat", "cool", "dry", "fan", "off"]
    temperature : 77.9
    thermostatFanMode : auto
    thermostatMode : heat
    thermostatOperatingState : heating
    thermostatSetpoint : 87.8

Looks like min max fields are interfering:

[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:02.023 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature: Temperature adjusted to 32.0 for Salon AC
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:02.015 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature_KumoCloud: Unit Command submitted
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:02.008 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)unitCommand: Initial data returned from unitCommand: [true, null, [[9934P008M100125F, 2253895757941193]]], response received 2022-11-24 15:44:01.999Z
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.566 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)unitCommand_KumoCloud: Body of command = ["314bb30643c955d11e1e39909bcebe70",{"9934P008M100125F":{"spHeat":0.0}}]
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.550 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature_KumoCloud: Body JSON = {"spHeat":0.0}
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.540 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature: Set Temperature Provided = 32.0, converted to 0 for KumoCloud
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.522 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustHeatingSetpoint: Current heatingSetpoint 32.0, Current ThermostatSetpoint = 32.0, New heatingSetpoint = 32.0
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.514 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustSetTemperature: Heating mode detected, adjusting heating set point
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.507 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustSetTemperature: Current mode is heat
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.498 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustSetTemperature: Changing Set Temperature from 87.8 to 32.0
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.491 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustSetTemperature: Temperature passed in was 32 which was parsed as 32.0, current set temperature is 87.8
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.483 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature: Setting Temperature to 32.0 for Salon AC
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.476 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setTemperature: givenSetTemp = 32, currentThermSetTempValue = 87.8
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.455 AM[info](https://hubitat/logs?tab=past&deviceId=780#)Heating Set Point adjusted to 32.0 for Salon AC
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.447 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)adjustHeatingSetpoint: Current heatingSetpoint 87.8, Current ThermostatSetpoint = 87.8, New heatingSetpoint = 32.0
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.439 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setHeatingSetpoint: Corrected Temp = 32
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.433 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setHeatingSetpoint: Temperature selected = 60, corrected to maximum heating set point 32
[dev:780](https://hubitat/logs?tab=past&deviceId=780#)2022-11-24 10:44:01.425 AM[debug](https://hubitat/logs?tab=past&deviceId=780#)setHeatingSetpoint: Setting Heating Set Point to 60, current minimum 32, current maximum 32

also noticed this little tidbit:

[dev:780]2022-11-24 10:37:17.748 AM[error]retrieveUnitSettings_KumoCloud : Unable to query Mitsubishi Electric KumoCloud: java.lang.NullPointerException: Cannot get property 'min_setpoint' on null object
Lcstyle commented 2 years ago

could it be something as simple as the field names you're looking for have been renamed, and without finding them, the default temp of 0C or 32F is being set?


reportedProfile:[fan_speed_stages:5, has_air_direction:true, has_auto_fan_speed:true, has_dry_function:true, has_extended_temp_range:true, has_heat_function:true, has_swing_direction:true, has_test_run:false, has_unit_function_setting:false, has_ventilation_function:true, display_setting_temp_of_dry:true, maximum_auto_temp:31, maximum_cool_or_dry_temp:31, maximum_heat_temp:31, minimum_auto_temp:16, minimum_cool_or_dry_temp:16, minimum_heat_temp:10], sendDesiredConditionsPending:true, sendDesiredConditionsTime:2021-12-21T20:02:36.533Z, systemChangeoverEnabled:false, minCoolSetpoint:16, maxHeatSetpoint:31, kumoSensorSettings:null, address:10.0.1.56, _requestRescan:0, _isRespondingLocally:null, autoChangeoverEnabled:false, optimalStart:false]]```
Lcstyle commented 1 year ago

@sburke781 your latest update overwrote my code and broke my temperatures again, since package manager was set to auto update. I pasted my code back in and turned off auto updates in package manager.

your fan modes and auto detection are broken as well BTW. You can refer to the following operating manual for modes/fan modes: https://www.powerequipmentdirect.com/manuals/b68b8fa4726e60c17e68db8751659837.pdf

If you need me to provide you with a raw data dump of the kumo cloud calls, kindly let me know, I would be happy to share with you in private.

import java.text.DecimalFormat;

metadata {
    definition (name: "Unified Thermostat Unit Child Driver", namespace: "simnet", author: "Simon Burke") {
        capability "Refresh"
        capability "Initialize"
        capability "Thermostat"
        capability "FanControl"
        capability "TemperatureMeasurement"

preferences {
        input(name: "AutoStatusPolling", type: "bool", title:"Automatic Status Polling", description: "Enable / Disable automatic polling of unit status", defaultValue: true, required: true, displayDuringSetup: true)
        input(name: "StatusPollingInterval", type: "ENUM", multiple: false, options: ["1", "2", "5", "10", "30", "60"], title:"Status Polling Interval", description: "Number of minutes between automatic status updates", defaultValue: 10, required: true, displayDuringSetup: true)     
        input(name: "FansTextOrNumbers", type: "bool", title: "Fan Modes: Text or Numbers?", description: "Use Text for Fan Modes (ON) or Numbers (OFF)?", defaultValue: true, required: true, displayDuringSetup: true)
    }

        attribute "unitId",                 "string"
        attribute "TemperatureIncrement",   "number"  // e.g. 0.5

        //Temperature Ranges
        attribute "MinTempCool",            "number"  // e.g. 16.0
        attribute "MaxTempCool",            "number"  // e.g. 31.0
        attribute "MinTempDry",             "number"  // e.g. 16.0
        attribute "MaxTempDry",             "number"  // e.g. 31.0
        attribute "MinTempHeat",            "number"  // e.g. 10.0
        attribute "MaxTempHeat",            "number"  // e.g. 31.0
        attribute "MinTempAuto",            "number"  // e.g. 16.0
        attribute "MaxTempAuto",            "number"  // e.g. 31.0

        //Modes and Features
        attribute "CanHeat",                "string"  // e.g. true / false
        attribute "CanDry",                 "string"  // e.g. true / false
        attribute "CanCool",                "string"  // e.g. true / false
        attribute "HasAutomaticFanSpeed",   "string"  // e.g. true / false
        attribute "NumberOfFanSpeeds",      "number"  // e.g. 5
        attribute "lastRunningMode",                "STRING"
        attribute "lastCommandUTC",                 "STRING"
    }
}

def getUnitId() {

    return state.unitId
}

def setUnitId(pUnitId) {

    state.unitId = pUnitId
}

// Standard Driver Methods

/* Initialize() To-Do
      1. Come up with updated logic for handling high set point to take into account
           Celsius and Fahrenheit

*/

def initialize() {

    parent.debugLog("initialize: Initialize process started for unit ${getUnitId()}...")
    //update unit settings and status polling
    updated()
    //Run refresh process, including status updates for power, mode, temperatures, etc
    refresh()
    parent.debugLog("initialize: Initialize process completed for unit ${getUnitId()}...")
}

def refresh() {
    parent.debugLog("refresh: Refresh process called")

    // Retrieve current state information and apply updates
    //   to HE device attributes
    applyStatusUpdates(retrieveStatusInfo())   
}

// Updated - Run when the Save Preferences button is pressed on the Device Edit page
//            and when device is initialized
//        To-Do: Turn on polling
def updated() {

    // Retrieve current unit settings and features, applying updates
    //   to HE device attributes
    parent.debugLog("updated: Applying Unit Settings and Features for unit ${getUnitId()}...")
    applyUnitSettings(retrieveUnitSettings())
    parent.debugLog("updated: AutoStatusPolling = ${AutoStatusPolling}, StatusPollingInterval = ${StatusPollingInterval}")
    updateStatusPolling()
}

// Mode and Fan Mode Maps and Conversions

/* getFanModeMap() To-Do: Review these values for Kumo and MelView */
def getFanModeMap() {
    if (FansTextOrNumbers == true) {
        [
            "0":"Auto",
            "1":"Quiet",
            "2":"Low",
            "3":"Medium",
            "5":"High",
            "6":"Very High"
        ]
    }
    else {
        [
            "0":"auto",
            "1":"1",
            "2":"2",
            "3":"3",
            "5":"5",
            "6":"6"
        ]
    }
}

/* convertFanModeToKey() To-Do: Confirm mode values across each platform */
def convertFanModeToKey(pFanMode) {

    String vFanMode = "${pFanMode}";
    vFanMode = vFanMode.trim().toLowerCase();
    def vModeKey = null
    if(vFanMode == "auto"        || vFanMode == "auto")   { vModeKey = 0 }
    if(vFanMode == "quiet"       || vFanMode == "1"   )   { vModeKey = 1 }
    if(vFanMode == "low"         || vFanMode == "2"   )   { vModeKey = 2 }
    if(vFanMode == "medium"      || vFanMode == "3"   )   { vModeKey = 3 }
    if(vFanMode == "high"        || vFanMode == "5"   )   { vModeKey = 5 }
    if(vFanMode == "very-high"   || vFanMode == "6"   )   { vModeKey = 6 }

    return vModeKey
}

def adjustFanModes(pNumberOfFanSpeeds, pHasAutomaticFanSpeed) {
    def fanModes = []

    //Text or Numbers?
    if (FansTextOrNumbers == true || FansTextOrNumbers == "1") {
        log.debug("adjustFanModes:Text-based Fan Modes")
            fanModes.add("\"Auto\"")
            fanModes.add("\"Quiet\"")
            fanModes.add("\"Low\"")
            fanModes.add("\"Medium\"")
            fanModes.add("\"High\"")
            fanModes.add("\"Very High\"")
        }
    else {
            fanModes.add("\"0\"")
            fanModes.add("\"1\"")
            fanModes.add("\"2\"")
            fanModes.add("\"3\"")
            fanModes.add("\"5\"")
            fanModes.add("\"6\"")
        }

    log.debug("adjustFanModes: fanModes detected are ${fanModes}")
    //Apply settings
    sendEvent(name: 'supportedThermostatFanModes', value: fanModes)

    parent.debugLog("adjustFanModes: fanModes detected are ${fanModes}")
    //Apply settings
    sendEvent(name: 'supportedThermostatFanModes', value: fanModes)
}

/* getModeMap() To-Do: Review these values for Kumo and MelView */
def getModeMap() {
    [
        "1"  : "heat",
        "2"  : "dry",
        "3"  : "cool",
        "7"  : "fan",
        "8"  : "auto",
        "16" : "off",
        "33" : "auto",
        "35" : "auto"
    ]
}

def getOperatingStateMap() {
    [
        "1"  : "heating",
        "2"  : "drying",
        "3"  : "cooling",
        "7"  : "fan only",
        "8"  : "auto",
        "16" : "idle",
        "33" : "heating",
        "35" : "cooling"
    ]
}

def adjustThermostatModes(pCanHeat,pCanCool,pCanDry, pCanAuto) {

    parent.debugLog("adjustThermostatModes: Adjusting Thermostat Modes...")
    def thermostatModes = []
    parent.debugLog("adjustThermostatModes: CanHeat = ${pCanHeat}, CanCool = ${pCanCool}, CanDry = ${pCanDry}, CanAuto = ${pCanAuto}")
    thermostatModes.add("\"heat\"") 
    thermostatModes.add("\"cool\"")
    thermostatModes.add("\"dry\"")
    thermostatModes.add("\"auto\"")
    thermostatModes.add("\"fan\"")
    thermostatModes.add("\"off\"")

    parent.debugLog("adjustThermostatModes: thermostatModes detected are ${thermostatModes}")
    sendEvent(name: 'supportedThermostatModes', value: thermostatModes)

}

/* convertThermostatModeToKey() To-Do: Confirm mode values across each platform */
def convertThermostatModeToKey(pThermostatMode) {

    def vModeKey = null
    if(pThermostatMode.trim() == "heat")   vModeKey = 1
    if(pThermostatMode.trim() == "dry")    vModeKey = 2
    if(pThermostatMode.trim() == "cool")   vModeKey = 3
    if(pThermostatMode.trim() == "fan")    vModeKey = 7
    if(pThermostatMode.trim() == "auto")   vModeKey = 8

    return vModeKey
}

// Unit Settings and Status

def retrieveUnitSettings() {

    //Returns current features and settings information for the ac unit
    def settings = [:]
    parent.debugLog("retrieveUnitSettings: Retrieving unit features and settings")
    settings = "retrieveUnitSettings_${parent.getPlatform()}"()

    parent.debugLog("retrieveUnitSettings: pre-conversion")

    settings.minTempCool = settings.minTempCool
    settings.maxTempCool = settings.maxTempCool
    settings.minTempDry  = settings.minTempDry
    settings.maxTempDry  = settings.maxTempDry
    settings.minTempHeat = settings.minTempHeat
    settings.maxTempHeat = settings.maxTempHeat
    settings.minTempAuto = settings.minTempAuto
    settings.maxTempAuto = settings.maxTempAuto

    parent.debugLog("retrieveUnitSettings: Settings to be returned = ${settings}")
    return settings

}

def retrieveUnitSettings_KumoCloud() {

    parent.debugLog("retrieveUnitSettings_KumoCloud: Retrieval process started...")

    def settings = [:]
    def postParams = [
        uri: "${parent.getBaseURL()}/getInfrequentDeviceUpdates",
        headers: parent.getStandardHTTPHeaders_KumoCloud("no"),
        contentType: "application/json; charset=UTF-8",
        body : "[ \"${parent.getAuthCode()}\",[\"${getUnitId()}\"] ]"
    ]

    try {

        httpPost(postParams) { resp ->

            parent.debugLog("retrieveUnitSettings_KumoCloud: Initial data returned: ${resp.data}")
            //Temperature Ranges Configured

                settings.minTempCool  = "60"
                settings.maxTempCool  = "60"
                settings.minTempDry   = "60"
                settings.maxTempDry   = "60"
                settings.minTempHeat  = "50"
                settings.maxTempHeat  = "88"
                settings.minTempAuto  = "60"
                settings.maxTempAuto  = "88"

            //Modes and Features
            settings.canHeat              = "true"
            settings.canDry               = "true"
            settings.canCool              = "true"
            settings.canAuto              = "true"
            settings.hasAutomaticFanSpeed = "true"
            settings.numberOfFanSpeeds    = "5"
        }
    }   
    catch (Exception e) {
        parent.errorLog "retrieveUnitSettings_KumoCloud : Unable to query Mitsubishi Electric KumoCloud: ${e}"
    }

    return settings
}

def applyUnitSettings(givenSettings) {

    parent.debugLog("applyUnitSettings: Unit Settings are ${givenSettings}")
    //Temperature Ranges Configured
    sendEvent(name: "MinTempCool", value: givenSettings.minTempCool)
    sendEvent(name: "MaxTempCool", value: givenSettings.maxTempCool)
    sendEvent(name: "MinTempDry" , value: givenSettings.minTempDry)
    sendEvent(name: "MaxTempDry" , value: givenSettings.maxTempDry)
    sendEvent(name: "MinTempHeat", value: givenSettings.minTempHeat)
    sendEvent(name: "MaxTempHeat", value: givenSettings.maxTempHeat)
    sendEvent(name: "MinTempAuto", value: givenSettings.minTempAuto)
    sendEvent(name: "MaxTempAuto", value: givenSettings.maxTempAuto)

    //Modes and Features
    sendEvent(name: "CanHeat",              value: givenSettings.canHeat)
    sendEvent(name: "CanCool",              value: givenSettings.canCool)
    sendEvent(name: "CanDry",               value: givenSettings.canDry)
    sendEvent(name: "CanAuto",              value: givenSettings.canAuto)
    sendEvent(name: "HasAutomaticFanSpeed", value: givenSettings.hasAutomaticFanSpeed)
    sendEvent(name: "NumberOfFanSpeeds",    value: givenSettings.numberOfFanSpeeds)

    adjustFanModes(givenSettings.numberOfFanSpeeds, givenSettings.hasAutomaticFanSpeed)
    adjustThermostatModes(givenSettings.canHeat, givenSettings.canCool, givenSettings.canDry, givenSettings.canAuto)
}

def retrieveStatusInfo() {

    //Returns current status information for the ac unit
    parent.debugLog("retrieveStatusInfo: Retrieving status info from ${parent.getPlatform()} ")
    def statusInfo = "retrieveStatusInfo_${parent.getPlatform()}"()
    statusInfo.setTemp  = convertTemperatureIn(statusInfo.setTemp)
    statusInfo.roomTemp = convertTemperatureIn(statusInfo.roomTemp)

    return statusInfo

}

def retrieveStatusInfo_KumoCloud() { 

    def statusInfo = [:]
    def postParams = [
        uri: "${parent.getBaseURL()}/getDeviceUpdates",
        headers: parent.getStandardHTTPHeaders_KumoCloud("no"),
        contentType: "application/json",
        body : "[ \"${parent.getAuthCode()}\",[\"${getUnitId()}\"] ]"
    ]

    try {

        httpPost(postParams) { acUnit ->
                                 parent.debugLog("retrieveStatusInfo_KumoCloud: response - ${acUnit.data}")     
                                 statusInfo.unitId     = "${acUnit.data[2][0].device_serial}".replace("[","").replace("]","")
                                 statusInfo.statusAsAt = "${acUnit.data[2][0].record_time}".replace("[","").replace("]","")

                                 //Current Status Information
                                 statusInfo.power      = "${acUnit.data[2][0].power}".replace("[","").replace("]","")
                                 statusInfo.setMode    = "${acUnit.data[2][0].operation_mode}".replace("[","").replace("]","")
                                 statusInfo.roomTemp   = "${acUnit.data[2][0].room_temp}".replace("[","").replace("]","")

                                 if(statusInfo.setMode == "3" || statusInfo.setMode == "35") { statusInfo.setTemp  = "${acUnit.data[2][0].sp_cool}".replace("[","").replace("]","") }
                                 if(statusInfo.setMode == "1" || statusInfo.setMode == "33") { statusInfo.setTemp  = "${acUnit.data[2][0].sp_heat}".replace("[","").replace("]","") }
                                 //statusInfo.setTemp  = "${acUnit.data[2][0].set_temp}".replace("[","").replace("]","")

                                 statusInfo.setFan   = "${acUnit.data[2][0].fan_speed}".replace("[","").replace("]","")

                            }
        parent.debugLog("retrieveStatusInfo_KumoCloud: Status Info - ${statusInfo}")
    }   
    catch (Exception e) {
        parent.errorLog("retrieveStatusInfo_KumoCloud: Unable to query Mitsubishi Electric Kumo Cloud: ${e}")
    }

    return statusInfo
}

def applyStatusUpdates(statusInfo) {
    def statusIsCurrent = 1
    parent.debugLog("applyResponseStatus: Status Info: ${statusInfo}")

    if (!statusInfo.isEmpty()) {
        parent.debugLog("applyResponseStatus: lastCommandUTC = ${checkNull(device.currentValue("lastCommandUTC", true),"Null")}, ${checkNull(statusInfo.statusAsAt,"Null")}")
        if (device.currentValue("lastCommandUTC") != null && statusInfo.containsKey("statusAsAt") ) {

            def lastCommandUTC_Date = new java.text.SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS'Z'" ).parse(device.currentValue("lastCommandUTC", true))
            def statusAsAt_Date = new java.text.SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ).parse(statusInfo.statusAsAt)
            parent.debugLog("applyResponseStatus: lastCommandUTC_Date = ${lastCommandUTC_Date}, statusAsAt_Date = ${statusAsAt_Date}")

            if (lastCommandUTC_Date > statusAsAt_Date) {
               statusIsCurrent = 0 
            }
            else { statusIsCurrent = 1 }
        }
        else { statusIsCurrent = 1 }
        parent.debugLog("applyStatusUpdates: statusIsCurrent = ${statusIsCurrent}")
        if (statusIsCurrent == 1) {
            parent.debugLog("applyStatusUpdates: About to adjust thermostat mode details...")
            adjustThermostatMode(statusInfo.setMode, statusInfo.power)
            parent.debugLog("applyStatusUpdates: About to adjust temperatures...")
            adjustRoomTemperature(statusInfo.roomTemp)
            adjustSetTemperature(statusInfo.setTemp, statusInfo.setMode, statusInfo.power)
            adjustThermostatFanMode(statusInfo.setFan)
        }
        else { parent.debugLog("applyResponseStatus: Status information is out of date, a command must have been run recently") }
        parent.debugLog("applyResponseStatus: Status update complete")
    }
    else { parent.debugLog("applyResponseStatus: No status information was provided, no further action was taken") }
}

// Unit Control Methods
// Temperature Control

def adjustRoomTemperature(pTemp) {

  def vTempScaleUnit = "°${parent.getHETempScale()}"
  def vRoomTempValue

  parent.debugLog("adjustRoomTemperature: Temperature provided = ${pTemp}")
  if(pTemp == null || !"${pTemp}".isNumber()) {

      parent.warnLog("adjustRoomTemperature: Warning, The Room Temperature was either null or not a number")
  }
  else {
        vRoomTempValue = pTemp.toFloat().round(1)
        if (device.currentValue("temperature", true) == null || device.currentValue("temperature", true).toFloat().round(1) != vRoomTempValue) {
            if (device.currentValue("temperature", true) != vRoomTempValue) { parent.debugLog("adjustRoomTemperature: Current Room Temperature value and value provided did not match") }
              parent.debugLog("adjustRoomTemperature: updating room temperature from ${device.currentValue("temperature", true)} to ${vRoomTempValue}")
              sendEvent(name: "temperature", value: vRoomTempValue)
          }
        else { parent.debugLog("adjustRoomTemperature: No action taken") }
  }
}

// adjustHeatingSetpoint() To-Do: Use Minimum Heating Set Point instead of 23
def adjustHeatingSetpoint(givenTemp) {
    def heatingSetTempValue = givenTemp.toFloat().round(1)
    def currHeatingSetTempValue = checkNull(device.currentValue("heatingSetpoint", true),"23.0").toFloat().round(1)
    def currThermSetTempValue = checkNull(device.currentValue("thermostatSetpoint", true),"23.0").toFloat().round(1)

    parent.debugLog("adjustHeatingSetpoint: Current heatingSetpoint ${currHeatingSetTempValue}, Current ThermostatSetpoint = ${currThermSetTempValue}, New heatingSetpoint = ${heatingSetTempValue}")

    if (currHeatingSetTempValue != heatingSetTempValue) {
        sendEvent(name: "heatingSetpoint", value : heatingSetTempValue)
        parent.infoLog("Heating Set Point adjusted to ${heatingSetTempValue} for ${device.label}")
    }
}

def setHeatingSetpoint(givenTemp) {
    def correctedTemp = givenTemp
    parent.debugLog("setHeatingSetpoint: Setting Heating Set Point to ${givenTemp}, current minimum ${device.currentValue("MinTempHeat", true)}, current maximum ${device.currentValue("MaxTempHeat", true)}")
    //Maximum
    if (givenTemp > device.currentValue("MaxTempHeat", true)) {
        correctedTemp = device.currentValue("MaxTempHeat", true)
        parent.debugLog("setHeatingSetpoint: Temperature selected = ${givenTemp}, corrected to maximum heating set point ${correctedTemp}")
    }
    parent.debugLog("setHeatingSetpoint: Corrected Temp = ${correctedTemp}")
    adjustHeatingSetpoint(correctedTemp)
    if (device.currentValue("thermostatOperatingState", true) == "heating") { setTemperature(correctedTemp) }
}

// adjustCoolingSetpoint() To-Do: Use Maximum Heating Set Point instead of 23
def adjustCoolingSetpoint(givenTemp) {

    def coolingSetTempValue = givenTemp.toFloat().round(1)
    def currCoolingSetTempValue = checkNull(device.currentValue("coolingSetpoint", true),"23.0").toFloat().round(1)
    def currThermSetTempValue = checkNull(device.currentValue("thermostatSetpoint", true),"23.0").toFloat().round(1)

    parent.debugLog("adjustCoolingSetpoint: Current coolingSetpoint ${currCoolingSetTempValue}, Current ThermostatSetpoint = ${currThermSetTempValue}, New coolingSetpoint = ${coolingSetTempValue}")

    if (currCoolingSetTempValue != coolingSetTempValue) {
        sendEvent(name: "coolingSetpoint", value : coolingSetTempValue)
        parent.infoLog("Cooling Set Point adjusted to ${coolingSetTempValue} for ${device.label}")
    }
}

def setCoolingSetpoint(givenTemp) {

    def correctedTemp = givenTemp

    parent.debugLog("setCoolingSetpoint: Setting Cooling Set Point to ${givenTemp}, current minimum ${device.currentValue("MinTempCool", true)}, current maximum ${device.currentValue("MaxTempCool", true)}")

    //Check allowable cooling temperature range and correct where necessary
    //Minimum
    if (givenTemp < device.currentValue("MinTempCool", true)) {
        correctedTemp = device.currentValue("MinTempCool", true)
        parent.debugLog("setCoolingSetpoint: Temperature selected = ${givenTemp}, corrected to minimum cooling set point ${correctedTemp}")
    }

    parent.debugLog("setCoolingSetpoint: Corrected Temp = ${correctedTemp}")
    adjustCoolingSetpoint(correctedTemp)
    if (device.currentValue("thermostatOperatingState", true) == "cooling" || device.currentValue("thermostatOperatingState", true) == "drying") { setTemperature(correctedTemp) }
}

// TO-DO: Look at use of the value 23.0 for the US
//        Tidy up use of conversions and checks and logging, particularly when we get a null value returned from API
def adjustSetTemperature(pSetTemp, pThermostatMode, pPower) {

    def vSetTemp
    if ("${pSetTemp}".isNumber()) { vSetTemp = pSetTemp.toFloat().round(1) }
    else { vSetTemp = null }

    def vCurrentSetTempConv
    def vCurrentSetTemp = device.currentValue("thermostatSetpoint", true)
    if ("${vCurrentSetTemp}".isNumber()) { vCurrentSetTempConv = vCurrentSetTemp.toFloat().round(1)}
    else { vCurrentSetTempConv = null }
    parent.debugLog("adjustSetTemperature: Temperature passed in was ${pSetTemp} which was parsed as ${vSetTemp}, current set temperature is ${vCurrentSetTempConv}")

    if (vSetTemp != null && (vCurrentSetTempConv == null || vCurrentSetTempConv != vSetTemp)) {

        parent.debugLog("adjustSetTemperature: Changing Set Temperature from ${vCurrentSetTempConv} to ${vSetTemp}")
        sendEvent(name: "thermostatSetpoint", value: vSetTemp)

        def vMode
        if (pMode == null) { vMode = device.currentValue("thermostatMode", true) }
        else { vMode = deriveThermostatMode(pThermostatMode, pPower) }

        parent.debugLog("adjustSetTemperature: Current mode is ${vMode}")

        if (vMode == "heat") {
            parent.debugLog("adjustSetTemperature: Heating mode detected, adjusting heating set point")
            adjustHeatingSetpoint(vSetTemp)
        }

        if (vMode == "cool" || vMode == "dry") {
            parent.debugLog("adjustSetTemperature: Cooling / Drying mode detected, adjusting cooling set point")
            adjustCoolingSetpoint(vSetTemp)
        }

    }
    else { parent.debugLog("adjustSetTemperature: No action taken, either no change in temperature or null temperature provided") }
}

def setTemperature(givenSetTemp) {

    def vPlatform = parent.getPlatform()
    def setTempValue = givenSetTemp.toFloat().round(1)
    def currThermSetTempValue = checkNull(device.currentValue("thermostatSetpoint", true),"23.0").toFloat().round(1)
    def convertedTemp = setTempValue
    parent.debugLog("setTemperature: givenSetTemp = ${givenSetTemp}, currentThermSetTempValue = ${currThermSetTempValue}")
    if(currThermSetTempValue != setTempValue) {
        parent.debugLog("setTemperature: Setting Temperature to ${setTempValue} for ${device.label}")
        adjustSetTemperature(givenSetTemp, null, null)

        convertedTemp = convertTemperatureOut("${givenSetTemp}")
        parent.debugLog("setTemperature: Set Temperature Provided = ${setTempValue}, converted to ${convertedTemp} for ${vPlatform}")

        setTemperature_KumoCloud(convertedTemp)

        parent.debugLog("setTemperature: Temperature adjusted to ${setTempValue} for ${device.label}")
    }
    else {
        parent.debugLog("setTemperature: No action taken")
    }
}

def setTemperature_KumoCloud(givenSetTemp) {

    def setTempValue = givenSetTemp.toFloat()
    def bodyJson = "{\"sp${device.currentValue("thermostatMode", true).toLowerCase().capitalize()}\":${setTempValue}}"
    parent.debugLog("setTemperature_KumoCloud: Body JSON = ${bodyJson}")

    unitCommand_KumoCloud("${bodyJson}")
    parent.debugLog("setTemperature_KumoCloud: Unit Command submitted")
}

// Fan Mode Control

def adjustThermostatFanMode(pFanModeKey) {

    // Convert the MEL Fan Mode Key provided to a Fan Mode and Speed recognised by HE
    def vFanModeValue    = fanModeMap["${pFanModeKey}"].trim()
    def vFanControlSpeed = ""

    if(vFanModeValue == "Auto"        || vFanModeValue == "0")   vFanControlSpeed = "auto"
    if(vFanModeValue == "Quiet"       || vFanModeValue == "1")   vFanControlSpeed = "quiet"
    if(vFanModeValue == "Low"         || vFanModeValue == "2")   vFanControlSpeed = "low"
    if(vFanModeValue == "Medium"      || vFanModeValue == "3")   vFanControlSpeed = "medium"
    if(vFanModeValue == "High"        || vFanModeValue == "5")   vFanControlSpeed = "high"
    if(vFanModeValue == "Very High"   || vFanModeValue == "6")   vFanControlSpeed = "very high"

    parent.debugLog("adjustThermostatFanMode: MEL Fan Mode Key ${checkNull(pFanModeKey,"")} parsed as HE Fan Mode Value ${checkNull(vFanModeValue,"")} and HE Fan Speed ${vFanControlSpeed}")

    // Adjust the Fan Mode
    if(vFanModeValue == null) { parent.warnLog("adjustThermostatFanMode: Warning - Unknown Fan Mode selected, no action taken") }
    else {
        // Adjust the thermostatFanMode Attribute
        if (checkNull(device.currentValue("thermostatFanMode", true),"") != vFanModeValue) {
                sendEvent(name: "thermostatFanMode", value: vFanModeValue)
                parent.debugLog("adjustThermostatFanMode: Fan Mode adjusted to ${vFanModeValue} for ${device.label} (${getUnitId()})")
        }
        else { parent.debugLog("adjustThermostatFanMode: No change to Fan Mode detected, no action taken") }
    }

    // Adjust the Fan Speed
    if(vFanControlSpeed == "") { parent.warnLog("adjustThermostatFanMode: Warning - Unknown Fan Speed selected, no action taken") }
    else {
        // Adjust the speed Attribute
        if (checkNull(device.currentValue("speed", true),"") != vFanControlSpeed) {
            sendEvent(name: "speed", value: vFanControlSpeed)
            parent.infoLog("Fan Speed adjusted to ${vFanControlSpeed} for ${device.label} (${getUnitId()})")
        }
        else { parent.debugLog("adjustThermostatFanMode: No change to Fan Speed detected, no action taken") }
    }

}

def setThermostatFanMode(pFanMode) {

    def vPlatform = parent.getPlatform()
    def vFanMode = pFanMode.trim()
    def vFanModeKey = convertFanModeToKey(vFanMode)
    parent.debugLog("setThermostatFanMode: HE Fan Mode ${pFanMode} parsed as Fan Mode Key ${vFanModeKey}")

    if (vFanModeKey != null) {
        if(checkNull(device.currentValue("thermostatFanMode", true),"") != vFanMode)
        {
            adjustThermostatFanMode(vFanModeKey)
            parent.debugLog("setThermostatFanMode: Setting Fan Mode to ${vFanMode}(${vFanModeKey}) for ${device.label} (${getUnitId()})")

            setThermostatFanMode_KumoCloud (vFanModeKey)

            parent.infoLog("Fan Mode set to ${vFanMode} for ${device.label} (${getUnitId()})")
        }
        else { parent.debugLog("setThermostatFanMode: No action taken")  }

    }
    else { parent.warnLog("setThermostatFanMode: Warning - Fan Mode ${pFanMode} not identified in Fan Mode List, no action taken") }
}

def setThermostatFanMode_KumoCloud (pFanModeKey) {

    unitCommand_KumoCloud("{\"fanSpeed\":${pFanModeKey}}")

}

//Fan Speed method from the Fan Control capability
//  Simply calling the Fan Mode method that is part of the Thermostat capability 
def setSpeed(pFanspeed) { setThermostatFanMode("${pFanspeed}") }

// Thermostat Mode Control

def adjustThermostatMode(pThermostatMode, pPower) {

    parent.debugLog("adjustThermostatMode: Adjust Thermostat Mode called")
    def vModeDesc = deriveThermostatMode(pThermostatMode, pPower)
    parent.debugLog("adjustThermostatMode: Thermostat Mode provided ${pThermostatMode}, Power provided ${pPower}, parsed as Mode Description ${vModeDesc}")

    if (checkNull(device.currentValue("thermostatMode", true),"") != vModeDesc) {
        sendEvent(name: "thermostatMode", value: vModeDesc)
        if (vModeDesc != "off" && checkNull(device.currentValue("lastRunningMode", true),"") != vModeDesc) {
            sendEvent(name: "lastRunningMode", value: vModeDesc)
        }
    }
    adjustThermostatOperatingState(pThermostatMode,pPower)
}

/* adjustThermostatOperatingState To-Do: use map for mode to state translation */
def adjustThermostatOperatingState(pThermostatMode, pPower) {

    def vOperatingState
    if (pPower == "1") { vOperatingState = operatingStateMap["${pThermostatMode}"] }
    else { vOperatingState = "idle" }

    parent.debugLog("adjustThermostatOperatingState: Thermostat Mode passed in = ${pThermostatMode}, Power passed in ${pPower}, OperatingState: ${vOperatingState}")
    if (checkNull(device.currentValue("thermostatOperatingState", true),"") != vOperatingState) {
        sendEvent(name: "thermostatOperatingState", value: vOperatingState)
    }    

}

def deriveThermostatMode(pThermostatMode, pPower) {

    def vModeDesc
    if (pPower == "1" || pPower == "true") { vModeDesc = modeMap["${pThermostatMode}"] }
    else { vModeDesc = "off" }

    return vModeDesc

}

def setThermostatMode(pThermostatMode) {

  parent.debugLog("setThermostatMode: Thermostat Mode passed in = ${pThermostatMode}")
  "${pThermostatMode}"()
  parent.debugLog("setThermostatMode: Thermostat Mode set")
}

def on() {

    parent.debugLog("on: Turning ON device ${device.label} (${getUnitId()})")
    "on_${parent.getPlatform()}"()
    parent.infoLog("Power turned ON for ${device.label} (${getUnitId()})")

    adjustThermostatMode(convertThermostatModeToKey("on"), "1")
    parent.debugLog("on: Thermostat Mode adjusted")
}

def on_KumoCloud() {
    unitCommand_KumoCloud("{\"power\":1}")
}

def off() {
    log.debug("off: Turning OFF device ${device.label} (${getUnitId()})")
    "off_${parent.getPlatform()}"()
    parent.infoLog("Power turned OFF for ${device.label} (${getUnitId()})")
    adjustThermostatMode(convertThermostatModeToKey("off"), "0")
    log.debug("off: Thermostat Mode adjusted")
}

def off_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":0}")
}

def heat() {

    adjustHeatingSetpoint(device.currentValue("thermostatSetpoint", true))

    parent.debugLog("heat: Adjusting Thermostat Mode to Heating for ${device.label} (${getUnitId()})")
    "heat_${parent.getPlatform()}"()
    parent.infoLog("Thermostat Mode set to Heating for ${device.label} (${getUnitId()})")

    adjustThermostatMode(convertThermostatModeToKey("heat"), "1")
    parent.debugLog("heat: Thermostat Mode adjusted")
}

def heat_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":1,\"operationMode\":1}")
}

def dry() {

    parent.debugLog("dry: Adjusting Thermostat Mode to Dry for ${device.label} (${getUnitId()})")
    "dry_${parent.getPlatform()}"()
    parent.infoLog("Thermostat Mode set to Dry for ${device.label} (${getUnitId()})")

    adjustThermostatMode(convertThermostatModeToKey("dry"), "1")
    parent.debugLog("dry: Thermostat Mode adjusted")
}

def dry_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":1,\"operationMode\":2}")
}

def cool_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":1,\"operationMode\":3}")
}

def fan() {

    parent.debugLog("fan: Adjusting Thermostat Mode to Fan for ${device.label} (${getUnitId()})")
    "fan_${parent.getPlatform()}"()
    parent.infoLog("Thermostat Mode set to Fan for ${device.label} (${getUnitId()})")

    adjustThermostatMode(convertThermostatModeToKey("fan"), "1")
    parent.debugLog("fan: Thermostat Mode adjusted")
}

def fan_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":1,\"operationMode\":7}")  
}

def auto() {

    parent.debugLog("auto: Adjusting Thermostat Mode to Auto for ${device.label} (${getUnitId()})")
    "auto_${parent.getPlatform()}"()
    parent.infoLog("Thermostat Mode set to Auto for ${device.label} (${getUnitId()})")  

    adjustThermostatMode(convertThermostatModeToKey("auto"), "1")
    parent.debugLog("auto: Thermostat Mode adjusted")
}

def auto_KumoCloud() {

    unitCommand_KumoCloud("{\"power\":1,\"operationMode\":8}")
}

// Platform Specific API Command Methods

def unitCommand_KumoCloud(pCommand) {

    def vBodyJson = "[\"${parent.getAuthCode()}\",{\"${getUnitId()}\":${pCommand}}]"
    parent.debugLog("unitCommand_KumoCloud: Body of command = ${vBodyJson}")
    def vPostParams = [
        uri: "${parent.getBaseURL()}/sendDeviceCommands/v2",
        headers: parent.getStandardHTTPHeaders_KumoCloud("no"),
        contentType: "application/json; charset=UTF-8",
        body : vBodyJson
    ]

    try {
        httpPost(vPostParams) { resp ->
            sendEvent(name: "lastCommandUTC", value: "${new Date().format("yyyy-MM-dd HH:mm:ss.SSS'Z'", TimeZone.getTimeZone('UTC'))}")
            parent.debugLog("unitCommand: Initial data returned from unitCommand: ${resp.data}, response received ${new Date().format("yyyy-MM-dd HH:mm:ss.SSS'Z'", TimeZone.getTimeZone('UTC'))}")
          }
    }   
    catch (Exception e) {
        parent.errorLog "unitCommand_KumoCloud : Unable to query Mitsubishi Electric ${parent.getPlatform()}: ${e}"
    }

}

// Scheduled Status Update Methods

def getSchedule() { }

def updateStatusPolling() {

   def vSchedule
   parent.debugLog("updateStatusPolling: Updating Status Polling called, about to unschedule refresh")
   unschedule("refresh")
   parent.debugLog("updateStatusPolling: Unscheduleing refresh complete")

   if(AutoStatusPolling == true) {

       vSchedule = "0 0/${StatusPollingInterval} * ? * * *"
       parent.debugLog("updateStatusPolling: Setting up schedule with settings: schedule(\"${vSchedule}\",refresh)")
       try{

           schedule("${vSchedule}","refresh")
       }
       catch(Exception e) {
           parent.debugLog("updateStatusPolling: Error - " + e)
       }

       parent.debugLog("updateStatusPolling: Scheduled refresh set")
   }
   else { parent.debugLog("updateStatusPolling: Automatic status polling is disabled, no further action was taken")  }
}

// Utility Methods

def checkNull(value, alternative) {

    if(value == null) { return alternative }
    return value

}

def convertTemperatureIn(BigDecimal pTemp) { return convertTemperatureIn("${pTemp}") }

def convertTemperatureIn(String pTemp) {

    def vPlatformScale = parent.getPlatformScale()
    def vHEScale = parent.getHETempScale()
    return convertTemperature(pTemp,vPlatformScale,vHEScale)
}

def convertTemperatureOut(BigDecimal pTemp) { return convertTemperatureOut("${pTemp}") }

def convertTemperatureOut(String pTemp) {

    def vPlatformScale = parent.getPlatformScale()
    def vHEScale = parent.getHETempScale()
    return convertTemperature(pTemp,vHEScale,vPlatformScale)
}

def convertTemperature(String pTemp, String pSourceScale, String pTargetScale) {

    def vTemp = pTemp

    if (pTemp == null || !pTemp.isNumber() || pSourceScale == null || pTargetScale == null) { vTemp = null }
    else {
        if(pSourceScale != pTargetScale) {
            if(pSourceScale == "C") { vTemp = (String) ((Float) ((int) (celsiusToFahrenheit(pTemp.toFloat()).toFloat().round(4) *2 + 0.5)) /2.0) }
            else { vTemp = fahrenheitToCelsius(pTemp.toFloat()).toString() }
        }
    }

    return vTemp
}
sburke781 commented 1 year ago

Apologies @Lcstyle , I should have mentioned the possibility of that happening. Glad you were able to recover from it.