Stelpro Ki Thermostat

Manufacturer: Stelpro
Model: STZW402WB+ (Z-wave model)

Loaded the driver from ST with modifications.

Pairing: shows as "Device"
Driver loads with modifications

Device shows in “Devices” and shows options. Poll will show the current temperature. No other controls work.

No generic z-wave thermostat available to test with.

Any update with this? Can you share you changes to this device?

I never got it to work correctly with Hubitat. Messed with it a week or so and moved on.

Just got done installing it on my network. I see i just needed to remove the physicalgraph and replace with hubitat. I was able to add and when i included the thermostat it picked that up. I can change heating set point,reporting temp back. This all just happen a couple of minutes ago. I have not tried other settings yet.

Cool. Last time I messed with it was when Hubitat was first released. I did the updates of the code but it still wasn't fully working. Been a long time so I would hope it works now :slight_smile: It works on every other system I have.

Is this working well now?

Here is an earlier one that I found that actually seems to work. All I did was change physicalgraph to hubitat. So far though this did control the heat setpoint and report back correctly. I also added refresh.

/**
 *  Modified version of the SmartThings Z-Wave Thermostat device handler for Stelpro STZW402+
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */


metadata {
  definition (name: "Stelpro STZW402+", namespace: "JoshConley", author: "Josh Conley") {
    capability "Actuator"
    capability "Temperature Measurement"
    capability "Thermostat"
    capability "Configuration"
    capability "Polling"
    capability "Sensor"
    capability "Refresh"      

    command "switchMode"
    command "tempUp"
    command "tempDown"

    fingerprint deviceId: "0x08"
    fingerprint inClusters: "0x43,0x40,0x44,0x31"
  }

  // simulator metadata
  simulator {
    status "heat"      : "command: 4003, payload: 01"
    status "eco"     : "command: 4003, payload: 11"

    status "heat 60"        : "command: 4303, payload: 01 09 3C"
    status "heat 68"        : "command: 4303, payload: 01 09 44"
    status "heat 72"        : "command: 4303, payload: 01 09 48"

    status "temp 58"        : "command: 3105, payload: 01 2A 02 44"
    status "temp 62"        : "command: 3105, payload: 01 2A 02 6C"
    status "temp 70"        : "command: 3105, payload: 01 2A 02 BC"
    status "temp 74"        : "command: 3105, payload: 01 2A 02 E4"
    status "temp 78"        : "command: 3105, payload: 01 2A 03 0C"
    status "temp 82"        : "command: 3105, payload: 01 2A 03 34"

    status "idle"     : "command: 4203, payload: 00"
    status "heating"    : "command: 4203, payload: 01"

    // reply messages
    reply "2502": "command: 2503, payload: FF"
  }

  tiles {
    multiAttributeTile(name:"thermostatFull", type:"thermostat", width:6, height:4) {
      tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
        attributeState("default", label:'${currentValue}', unit:"dF")
      }
      tileAttribute("device.temperature", key: "VALUE_CONTROL") {
        attributeState("VALUE_UP", action: "tempUp")
        attributeState("VALUE_DOWN", action: "tempDown")
      }
      tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
        attributeState("idle", backgroundColor:"#BDBDBD")
        attributeState("heating", backgroundColor:"#FF621E")
      }
      tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {
        attributeState("heat", label:'${name}')
        attributeState("eco", label:'${name}')
      }
      tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
        attributeState("default", label:'${currentValue}', unit:"dF")
      }
    }

    standardTile("mode", "device.thermostatMode", height: 2, width: 4, inactiveLabel: false, decoration: "flat") {
      state "heat", icon: "st.thermostat.heat", action:"switchMode", nextState:"eco"
      state "eco", label: "Eco Mode", icon: "st.nest.nest-leaf", action:"switchMode", nextState:"heat"
    }

    standardTile("refresh", "device.thermostatMode", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
      state "default", action:"polling.poll", icon:"st.secondary.refresh"
    }

    main "thermostatFull"
    details(["thermostatFull", "mode", "refresh"])
  }
}

def parse(String description)
{
  def map = createEvent(zwaveEvent(zwave.parse(description, [0x42:1, 0x43:2, 0x31: 3])))
  if (!map) {
    return null
  }

  def result = [map]
  if (map.isStateChange && map.name in ["heatingSetpoint","thermostatMode"]) {
    def map2 = [
      name: "thermostatSetpoint",
      unit: getTemperatureScale()
    ]
    if (map.name == "thermostatMode") {
      state.lastTriedMode = map.value

      map2.value = device.latestValue("heatingSetpoint")
      log.info "THERMOSTAT, latest heating setpoint = ${map2.value}"
    }
    else {
      def mode = device.latestValue("thermostatMode")
      log.info "THERMOSTAT, latest mode = ${mode}"

      if (map.name == "heatingSetpoint") {
        map2.value = map.value
        map2.unit = map.unit
      }
    }
    if (map2.value != null) {
      log.debug "THERMOSTAT, adding setpoint event: $map"
      result << createEvent(map2)
    }
  }

  if (map.isStateChange && map.name == "thermostatOperatingState") {
    map.displayed = false
  }

  log.debug "Parse returned $result"
  result
}

// Event Generation
def zwaveEvent(hubitat.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
{
  def cmdScale = cmd.scale == 1 ? "F" : "C"
  def map = [:]
  map.value = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)
  map.unit = getTemperatureScale()
  map.displayed = false
  switch (cmd.setpointType) {
    case 1:
      map.name = "heatingSetpoint"
      break;
    default:
      return [:]
  }
  // So we can respond with same format
  state.size = cmd.size
  state.scale = cmd.scale
  state.precision = cmd.precision


  map
}

def zwaveEvent(hubitat.zwave.commands.sensormultilevelv3.SensorMultilevelReport cmd)
{
  log.debug "Multilevel report: ${cmd.sensorType}"

  def map = [:]
  if (cmd.sensorType == 1) {
    map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision)
    map.unit = getTemperatureScale()
    map.name = "temperature"

    log.debug "Temperature ${map.value}"
  }
  map
}

def zwaveEvent(hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport cmd)
{
 def map = [:]
  switch (cmd.operatingState) {
    case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
      map.value = "idle"
      break
    case hubitat.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING:
      map.value = "heating"
      break
    default:
      log.warn "Unknown operating state: ${cmd.operatingState}"
  }
  map.name = "thermostatOperatingState"
  map
}

def zwaveEvent(hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
  def map = [:]
  switch (cmd.mode) {
    // Heat mode
    case hubitat.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
      map.value = "heat"
      break

    // ECO mode
    case '11':
      map.value = "eco"
      break
  }

  map.name = "thermostatMode"
  map
}

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
  log.debug "Zwave event received: $cmd"
}

def zwaveEvent(hubitat.zwave.Command cmd) {
  log.warn "Unexpected zwave command $cmd"
}

// Command Implementations
def poll() {
  delayBetween([
    zwave.sensorMultilevelV3.sensorMultilevelGet().format(), // current temperature
    zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(), // heating setpoint
    zwave.thermostatModeV2.thermostatModeGet().format(), // heat or eco
    zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format() // idle or heating
  ], 2300)
}

def quickSetHeat(degrees) {
  setHeatingSetpoint(degrees, 1000)
}

def setHeatingSetpoint(preciseDegrees, Integer delay = 30000) {
  def degrees = new BigDecimal(preciseDegrees).setScale(1, BigDecimal.ROUND_HALF_UP)
  log.trace "setHeatingSetpoint($degrees, $delay)"
  def deviceScale = state.scale ?: 1
  def deviceScaleString = deviceScale == 2 ? "C" : "F"
  def locationScale = getTemperatureScale()
  def p = (state.precision == null) ? 1 : state.precision
  def roundedDegrees = degrees

  def convertedDegrees
  if (locationScale == "C" && deviceScaleString == "F") {
    convertedDegrees = celsiusToFahrenheit(degrees)
  } else if (locationScale == "F" && deviceScaleString == "C") {
    convertedDegrees = fahrenheitToCelsius(degrees)
  } else {
    convertedDegrees = degrees
  }

  sendEvent(name: "heatingSetpoint", value: degrees, unit: locationScale)

  delayBetween([
    zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
    zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
  ], delay)
}

def relativeAdjustment(Integer sign) {
  def locationScale = getTemperatureScale()
  def heatingSetpoint = device.currentValue("heatingSetpoint")
  def adjustTo = heatingSetpoint

  if (locationScale == "C") {
    adjustTo += 0.5 * sign
  }
  else {
    adjustTo += 1 * sign
  }

  log.info "Adjust heating set point to ${adjustTo}${locationScale}"
  quickSetHeat(adjustTo)
}

def refresh() {
    poll()
}

def configure() {
  delayBetween([
    zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
    zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()
  ], 2300)
}

def modes() {
  ["heat", "eco"]
}

def switchMode() {
  def currentMode = device.currentState("thermostatMode")?.value
  def lastTriedMode = state.lastTriedMode ?: currentMode ?: "heat"
  def modeOrder = modes()
  def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
  def nextMode = next(lastTriedMode)
  state.lastTriedMode = nextMode
  delayBetween([
    zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[nextMode]).format(),
    zwave.thermostatModeV2.thermostatModeGet().format()
  ], 1000)
}

def switchToMode(nextMode) {
  if (nextMode in modes()) {
    state.lastTriedMode = nextMode
    "$nextMode"()
  } else {
    log.debug("no mode method '$nextMode'")
  }
}

def getDataByName(String name) {
  state[name] ?: device.getDataValue(name)
}

def getModeMap() { [
  "heat": 1,
  "eco": 11
]}

def setThermostatMode(String value) {
  delayBetween([
    zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[value]).format(),
    zwave.thermostatModeV2.thermostatModeGet().format()
  ], standardDelay)
}

def heat() {
  delayBetween([
    zwave.thermostatModeV2.thermostatModeSet(mode: 1).format(),
    zwave.thermostatModeV2.thermostatModeGet().format()
  ], standardDelay)
}

def eco() {
  delayBetween([
    zwave.thermostatModeV2.thermostatModeSet(mode: 11).format(),
    zwave.thermostatModeV2.thermostatModeGet().format()
  ], standardDelay)
}

def tempUp() {
  relativeAdjustment(1)
}

def tempDown() {
  relativeAdjustment(-1)
}

private getStandardDelay() {
  1000
}
1 Like

This one is working but has an issue where when the T-stat is on it constantly cycles from Idle to Heating. This happened in ST too but there was a switch on Devices Page that allowed turning off "Detailed Operating Status" Can anyone shed some light on how to do that here?

Discussion about how that worked was here:

update

Thanks for the help JrFarrar. I've noticed in my Google Home that it cannot communicate with the thermostat. Any ideas as to why?

There are some other threads on here discussing. This has nothing to do with this particular DH. It has to do with the Hubitat to Google integration. There were some ideas being tossed around about creating virtual switches of which Google could see then creating rules to turn up down heat using those. I think there are a few work arounds.

Has anyone used the Stelpro driver above in a routine and tried to use the mode switch to switch from Eco to Comfort and back? Those values don't seem to be available when you add the thermostat as a device to set in a routine. It does have "set mode" which translates to "set heat mode" on the Stelpro device, with the possibilities as off, auto, heat, emergency heat, and cool. But it does not have "Switch mode" which is just a push button to switch between Eco and Comfort. Am I missing something? Thanks...

Hi there, I am trying to do the same thing with a Stelpro SMT402. What do you mean when you say you 'remove the physical graph and replace with hubitat' I'm very new to this so some of the terminology is foreign to me.

Cheers,

Hi. I believe that Russ is talking about a change the he made in the SmartThings driver to make it work with Hubitat. "physicalgraph" is a field in the SmartThings driver. But you don't need to care about that since the modified driver is available. Just use it. Does this help?

Note: I forgot that this question was here. I have found the answer in another question somewhere else. Look at this and the dialog following to find the answer. Questions about Stelpro STZW402+ Z-wave Thermostat

Hi burns_hub, thanks for the quick response. I am actually working on a different Stelpro Thermostat. Mine is a Zigbee SMT402. I am trying to troubleshoot it, but the only info I can find is about the STZW402+. I'm taking the info from that and trying to reverse engineer (although I am very new to thtis so taking multiple shots in the dark).

Cheers,

I have a used STZW402WB+ that was paired to a ISY994 hub before.
I factory reset the thermostat, added the driver listed above by jrfarrar in hubitat (he claim it's an early version and his post is from 2018, anything newer driver available?)
but I can't pair the thermostat with hubitat.
any idea why?

1 Like