Iris Duraflame Heater

Can you post the working code?

Yes please post the working code, I am going to pick one up today. Thanks!

here is the code. @Sticks18 and myself are still working on it with the holiday and all but the functionality is there just has a few tweeks to workout.

/**

  • Copyright 2015 SmartThings
  • 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.
  • CentraLite Thermostat
  • Author: SmartThings
  • Date: 2013-12-02
    */
    metadata {
    definition (name: “Heater”, namespace: “smartthings”, author: “SmartThings”) {
    capability "Actuator"
    capability "Temperature Measurement"
    capability "Thermostat"
    capability "Configuration"
    capability "Power Meter"
    capability "Refresh"
    capability "Sensor"
    capability “Switch”

command "ecoOn"
command “ecoOff”

attribute “ecoMode”, “string”

fingerprint profileId: “0104”, inClusters: “0300,0000,0003,0006,0201,0204,0702,0B05”, outClusters: “0003,0019,0020”

}

// simulator metadata
simulator {
// status messages
status “on”: "on/off: 1"
status “off”: “on/off: 0”
// reply messages
reply “zcl on-off on”: "on/off: 1"
reply “zcl on-off off”: “on/off: 0”

}

tiles {
valueTile(“temperature”, “device.temperature”, width: 2, height: 2) {
state(“temperature”, label:’${currentValue}°’, unit:“F”,
backgroundColors:[
[value: 31, color: “#153591”],
[value: 44, color: “#1e9cbb”],
[value: 59, color: “#90d2a7”],
[value: 74, color: “#44b621”],
[value: 84, color: “#f1d801”],
[value: 95, color: “#d04e00”],
[value: 96, color: “#bc2323”]
]
)
}
standardTile(“switch”, “device.switch”, inactiveLabel: false, decoration: “flat”) {
state “off”, label:’${name}’, action:“switch.on”, icon:“st.switches.switch.off”, backgroundColor:"#ffffff"
state “on”, label:’${name}’, action:“switch.off”, icon:“st.switches.switch.on”, backgroundColor:"#79b821"
state “turningOn”, label:’${name}’, action:“switch.off”, icon:“st.switches.light.on”, backgroundColor:"#79b821", nextState:“turningOff"
state “turningOff”, label:’${name}’, action:“switch.on”, icon:“st.switches.light.off”, backgroundColor:”#ffffff", nextState:“turningOn”
}
controlTile(“heatSliderControl”, “device.heatingSetpoint”, “slider”, height: 1, width: 2, inactiveLabel: false, range: “(50…97)”) {
state “setHeatingSetpoint”, action:“thermostat.setHeatingSetpoint”, backgroundColor:"#d04e00"
}
valueTile(“heatingSetpoint”, “device.heatingSetpoint”, inactiveLabel: false, decoration: “flat”) {
state “heat”, label:’${currentValue}° heat’, unit:“F”, backgroundColor:"#ffffff"
}
standardTile(“refresh”, “device.temperature”, inactiveLabel: false, decoration: “flat”) {
state “default”, action:“refresh.refresh”, icon:“st.secondary.refresh”
}
standardTile(“ecoMode”, “device.ecoMode”, inactiveLabel: false, decoration: “flat”) {
state “off”, label:’${currentValue}’, action:“ecoOn”, icon:“st.switches.switch.off”, backgroundColor:"#ffffff"
state “on”, label:’${currentValue}’, action:“ecoOff”, icon:“st.switches.switch.on”, backgroundColor:"#79b821"
state “turningOn”, label:’${currentValue}’, action:“ecoOff”, icon:“st.switches.light.on”, backgroundColor:"#79b821", nextState:“turningOff"
state “turningOff”, label:’${currentValue}’, action:“ecoOn”, icon:“st.switches.light.off”, backgroundColor:”#ffffff", nextState:“turningOn”
}
valueTile (“power”, “device.power”, inactiveLabel: false, decoration: “flat”) {
state “power”, label:’${currentValue} W’, backgroundColor: “#ffffff
}
main "temperature"
details([“temperature”, “switch”, “heatSliderControl”, “heatingSetpoint”, “refresh”, “ecoMode”, “power”])

}
}

// parse events into attributes

def parse(String description) {
log.debug "Parse description $description"
def map = [:]
if (description?.startsWith(“read attr -”)) {
def descMap = parseDescriptionAsMap(description)
log.debug "Desc Map: $descMap"
if (descMap.cluster == “0201” && descMap.attrId == “0000”) {
log.debug "TEMP"
map.name = "temperature"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == “0201” && descMap.attrId == “0012”) {
log.debug "HEATING SETPOINT"
map.name = "heatingSetpoint"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == “0201” && descMap.attrId == “0025”) {
log.debug "EcoMode"
map.name = "ecoMode"
map.value = (descMap.value == “04” ? “on” : “off”)
} else if (descMap.cluster == “0201” && descMap.attrId == “001c”) {
log.debug "MODE"
map.name = "switch"
map.value = (descMap.value == “00” ? “off” : “on”)
} else if (descMap.cluster == “0702”) {
log.debug "Power"
map.name = "power"
map.value = convertHexToInt(descMap.value)
}
} else if (description?.startsWith(“catchall:”)) {
def msg = zigbee.parse(description)
log.trace msg
log.trace “data: $msg.data”
}

def result = null
if (map) {
result = createEvent(map)
}
log.debug "Parse returned $map"
return result
}

def parseDescriptionAsMap(description) {
(description - “read attr - “).split(”,”).inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}

def refresh() {
log.debug “refresh called”
[
“st rattr 0x${device.deviceNetworkId} 1 0x201 0”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x12”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x1C”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x25”, “delay 200”,
zigbee.simpleMeteringPowerRefresh()
]
}

def ecoOn() {
log.debug "ecoMode on"
sendEvent(name: “ecoMode”, value: “on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x25 0x18 {04}”
}

def ecoOff() {
log.debug "ecoMode off"
sendEvent(name: “ecoMode”, value: “off”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x25 0x18 {00}”
}

def getTemperature(value) {
if (value != null) {
def celsius = Integer.parseInt(value, 16) / 100
if (getTemperatureScale() == “C”) {
return celsius
} else {
return Math.round(celsiusToFahrenheit(celsius))
}
}
}

def setHeatingSetpoint(degrees) {
if (degrees != null) {
def temperatureScale = getTemperatureScale()
def degreesInteger = Math.round(degrees)
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent(“name”: “heatingSetpoint”, “value”: degreesInteger, “unit”: temperatureScale)

	def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
	"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"

}

}

def heat() {
log.debug "heat"
sendEvent(“name”:“thermostatMode”, “value”:“heat”)
sendEvent(“name”:“switch”, “value”:“on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {04}”
}

def on() {
log.debug "on"
sendEvent(“name”:“thermostatMode”, “value”:“auto”)
sendEvent(“name”:“switchStatus”, “value”:“on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {01}”
}

def off() {
log.debug "off"
sendEvent(“name”:“thermostatMode”, “value”:“off”)
sendEvent(“name”:“switch”, “value”:“off”)
sendEvent(“name”:“timer”, “value”:“off”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {00}”
}

private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}

private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}

private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}

private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j–;
i++;
}
return array
}

def configure() {

log.debug "binding to Thermostat cluster"
[
	"zdo bind 0x${device.deviceNetworkId} 1 1 0x201 {${device.zigbeeId}} {}", "delay 500",
	"zcl global send-me-a-report 0x201 0x0000 0x29 20 300 {19 00}",  // report temperature changes over 0.2C 
		"send 0x${device.deviceNetworkId} 1 1", "delay 500", 
	"zcl global send-me-a-report 0x201 0x001C 0x30 10 305 { }",  // mode 
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	"zcl global send-me-a-report 0x201 0x0025 0x18 10 310 { 00 }",  // schedule on/off
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	"zcl global send-me-a-report 0x201 0x0012 0x29 10 320 {32 00}", // cooling setpoint delta: 0.5C (0x3200 in little endian)
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	zigbee.simpleMeteringPowerConfig()
]

}

4 Likes

I have it working after changing the device type to the Centralite Thermostat device type. Have you done any further updates to remove cool and/or add the ECO mode? Thanks for getting this to work.

There is a newer code he made. I will post this evening

/**

  • Copyright 2015 SmartThings
  • 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.
  • CentraLite Thermostat
  • Author: SmartThings
  • Date: 2013-12-02
    */
    metadata {
    definition (name: “Heater”, namespace: “smartthings”, author: “SmartThings”) {
    capability "Actuator"
    capability "Temperature Measurement"
    capability "Thermostat"
    capability "Configuration"
    capability "Power Meter"
    capability "Refresh"
    capability "Sensor"
    capability "Switch"
    capability “Polling”

command "ecoOn"
command “ecoOff”

attribute “ecoMode”, “string”

fingerprint profileId: “0104”, inClusters: “0300,0000,0003,0006,0201,0204,0702,0B05”, outClusters: “0003,0019,0020”

}

// simulator metadata
simulator {
// status messages
status “on”: "on/off: 1"
status “off”: “on/off: 0”
// reply messages
reply “zcl on-off on”: "on/off: 1"
reply “zcl on-off off”: “on/off: 0”

}

tiles {
valueTile(“temperature”, “device.temperature”, width: 2, height: 2) {
state(“temperature”, label:’${currentValue}°’, unit:“F”,
backgroundColors:[
[value: 31, color: “#153591”],
[value: 44, color: “#1e9cbb”],
[value: 59, color: “#90d2a7”],
[value: 74, color: “#44b621”],
[value: 84, color: “#f1d801”],
[value: 95, color: “#d04e00”],
[value: 96, color: “#bc2323”]
]
)
}
standardTile(“switch”, “device.switch”, inactiveLabel: false, decoration: “flat”) {
state “off”, label:’${name}’, action:“switch.on”, icon:“st.switches.switch.off”, backgroundColor:"#ffffff"
state “on”, label:’${name}’, action:“switch.off”, icon:“st.switches.switch.on”, backgroundColor:"#79b821"
state “turningOn”, label:’${name}’, action:“switch.off”, icon:“st.switches.light.on”, backgroundColor:"#79b821", nextState:“turningOff"
state “turningOff”, label:’${name}’, action:“switch.on”, icon:“st.switches.light.off”, backgroundColor:”#ffffff", nextState:“turningOn”
}
controlTile(“heatSliderControl”, “device.heatingSetpoint”, “slider”, height: 1, width: 3, inactiveLabel: false, range: “(50…97)”) {
state “setHeatingSetpoint”, action:“thermostat.setHeatingSetpoint”, backgroundColor:"#d04e00"
}
valueTile(“heatingSetpoint”, “device.heatingSetpoint”, inactiveLabel: false, decoration: “flat”) {
state “heat”, label:’${currentValue}° heat’, unit:“F”, backgroundColor:"#ffffff"
}
standardTile(“refresh”, “device.temperature”, inactiveLabel: false, decoration: “flat”) {
state “default”, action:“refresh.refresh”, icon:“st.secondary.refresh”
}
standardTile(“ecoMode”, “device.ecoMode”, inactiveLabel: false, decoration: “flat”) {
state “Eco off”, label:’${currentValue}’, action:“ecoOn”, icon:“st.Outdoor.outdoor19”, backgroundColor:"#ffffff"
state “Eco on”, label:’${currentValue}’, action:“ecoOff”, icon:“st.Outdoor.outdoor19”, backgroundColor:"#79b821"
state “turningOn”, label:’${currentValue}’, action:“ecoOff”, icon:“st.Outdoor.outdoor19”, backgroundColor:"#79b821", nextState:“turningOff"
state “turningOff”, label:’${currentValue}’, action:“ecoOn”, icon:“st.Outdoor.outdoor19”, backgroundColor:”#ffffff", nextState:“turningOn”
}
main "temperature"
details([“temperature”, “switch”, “heatSliderControl”, “heatingSetpoint”, “ecoMode”, “refresh”])

}
}

// parse events into attributes

def parse(String description) {
log.debug "Parse description $description"
def map = [:]
if (description?.startsWith(“read attr -”)) {
def descMap = parseDescriptionAsMap(description)
log.debug "Desc Map: $descMap"
if (descMap.cluster == “0201” && descMap.attrId == “0000”) {
log.debug "TEMP"
map.name = "temperature"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == “0201” && descMap.attrId == “0012”) {
log.debug "HEATING SETPOINT"
map.name = "heatingSetpoint"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == “0201” && descMap.attrId == “0025”) {
log.debug "EcoMode"
map.name = "ecoMode"
map.value = (descMap.value == “04” ? “Eco on” : “Eco off”)
} else if (descMap.cluster == “0201” && descMap.attrId == “001c”) {
log.debug "MODE"
map.name = "switch"
map.value = (descMap.value == “00” ? “off” : “on”)
} else if (descMap.cluster == “0702”) {
log.debug "Power"
map.name = "power"
map.value = convertHexToInt(descMap.value)
}
} else if (description?.startsWith(“catchall:”)) {
def msg = zigbee.parse(description)
log.trace msg
log.trace “data: $msg.data”
}

def result = null
if (map) {
result = createEvent(map)
}
log.debug "Parse returned $map"
return result
}

def parseDescriptionAsMap(description) {
(description - “read attr - “).split(”,”).inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}

def poll() {
refresh()
}

def refresh() {
log.debug “refresh called”
[
“st rattr 0x${device.deviceNetworkId} 1 0x201 0”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x12”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x1C”, “delay 200”,
“st rattr 0x${device.deviceNetworkId} 1 0x201 0x25”, “delay 200”,
zigbee.simpleMeteringPowerRefresh()
]
}

def ecoOn() {
log.debug "ecoMode on"
sendEvent(name: “ecoMode”, value: “Eco on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x25 0x18 {04}”
}

def ecoOff() {
log.debug "ecoMode off"
sendEvent(name: “ecoMode”, value: “Eco off”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x25 0x18 {00}”
}

def getTemperature(value) {
if (value != null) {
def celsius = Integer.parseInt(value, 16) / 100
if (getTemperatureScale() == “C”) {
return celsius
} else {
return Math.round(celsiusToFahrenheit(celsius))
}
}
}

def setHeatingSetpoint(degrees) {
if (degrees != null) {
def temperatureScale = getTemperatureScale()
def degreesInteger = Math.round(degrees)
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent(“name”: “heatingSetpoint”, “value”: degreesInteger, “unit”: temperatureScale)

	def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
	"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"

}

}

def heat() {
log.debug "heat"
sendEvent(“name”:“thermostatMode”, “value”:“heat”)
sendEvent(“name”:“switch”, “value”:“on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {04}”
}

def on() {
log.debug "on"
sendEvent(“name”:“thermostatMode”, “value”:“auto”)
sendEvent(“name”:“switchStatus”, “value”:“on”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {01}”
}

def off() {
log.debug "off"
sendEvent(“name”:“thermostatMode”, “value”:“off”)
sendEvent(“name”:“switch”, “value”:“off”)
sendEvent(“name”:“timer”, “value”:“off”)
“st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {00}”
}

private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}

private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}

private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}

private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j–;
i++;
}
return array
}

def configure() {

log.debug "binding to Thermostat cluster"
[
	"zdo bind 0x${device.deviceNetworkId} 1 1 0x201 {${device.zigbeeId}} {}", "delay 500",
	"zcl global send-me-a-report 0x201 0x0000 0x29 20 300 {19 00}",  // report temperature changes over 0.2C 
		"send 0x${device.deviceNetworkId} 1 1", "delay 500", 
	"zcl global send-me-a-report 0x201 0x001C 0x30 10 305 { }",  // mode 
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	"zcl global send-me-a-report 0x201 0x0025 0x18 10 310 { 00 }",  // schedule on/off
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	"zcl global send-me-a-report 0x201 0x0012 0x29 10 320 {32 00}", // cooling setpoint delta: 0.5C (0x3200 in little endian)
		"send 0x${device.deviceNetworkId} 1 1","delay 500",
	zigbee.simpleMeteringPowerConfig()
]

}

def updated() {
configure()
}

2 Likes

@Sticks18 did all the code I just did the testing and interface inputs. Voice control doesn’t work on it yet…

It is cold in tampa and I love my heater @Sticks18

Ok so I am very new to the IoT. I currently only have an Iris hub and this duraflame heater. ideally I’d like to be able to get more connected devices and potentially have, at least some of them, run with Alexa on my Echo.

would the code posted above potentially allow this heater to be not only run by the SmartThings hub, but also with Alexa?

Looking at the code it implements the Thermostat and Switch capabilities. So you should be able to say…

“Alexa, set the header to 72 degrees”
“Alexa, turn on the heater”
“Alexa, turn off the heater”

I don’t have this heater so I can’t promise anything, but it looks like it will work.

@aquaria1984 @Sticks18 Thank you guys. I just bought one and used your DH and everything seems working good. Thank you. If you release a new version, please share it here.

1 Like

Hi Guys,

New to ST. Moved over from Wink for one reason because I bought this heater. I copied this code into a new DH and think I managed to configure everything correctly. When I added the new device ST recognized it. It seems to turn on if it’s off and seems to adjust the temperature up or down but ECO doesn’t seem to do anything and neither does the off switch. It also never shows the current temperature.

Any pointers? I’d really like to integrate this with my ecobee and have it come on when the ecobee comes on and turn off with the ecobee etc…

Thanks in advance for any assistance.

Cheers,

CM

Unfortunately I am still having problems. I have a number of non-standard devices that I have had to import device handlers for, so I believe I am doing things right, however when I try to pair the Duraflame heater it shows up as a “thing” rather than a heater, etc, and allows me to add it, but then states that the tile is missing in the UX. Unable to control it at all. Any ideas what I could be missing?

Shows up in IDE as follows:

Zigbee Id 000D6F000BFDDA7F
Data
application: 00
endpointId: 01
manufacturer: Twin-Star International
model: 20QI071ARA
Raw Description 01 0104 0300 00 06 0000 0003 0201 0204 0702 0B02 03 0003 0019 0020
Firmware
Current Version: 0x07045700
Target Version: 0x07045700

I can see similarities and differences in the raw description, but I am unsure what the impact is.

Thanks, Mark

I use this and works very well. If yours isn’t fixed, I can share the DH I customized for this.

I picked up the heater and used the latest DH found in this thread. The configure button doesn’t do anything. I am able to turn on / off and set the desired heat temp. I’d like to remove the cool mode and set point options since those are not applicable.

Are there any updates to the DH that address either of those. It’s not a major concern, just wanted to clean it up a bit. I suppose I can try to edit the DH and remove the functionality that doesn’t apply to this particular heater.

Now to test the 1000sq claim…

Thanks for the help.

@Sticks18 Thanks for the DTH for the Iris Duraflame heater just brought one and hook it up to my SmartThings and it works good and would also like to thanks @aquaria1984 for helping out. You all make this the best community. Thanks you all very much.

I have another question just came up. I have the App set up to heat to 60 degree as a set point but the heater goes to 66 or 67? Is anyone else having this issue? If so, how do I correct it?

Could you please post your device handler for this heater? No matter what I try, all I get is errors with the one listed above.

Thanks in Advance, JD

Sorry for the late reply. Here is what I use.

1 Like

Sorry for the old thread, but I’m looking to get voice control on this with Google home. I’ve installed the device handler with the latest code I’ve found in this thread (thank you everyone for implementing it! :)), and after adding it to smartthings (came in as a thing) and changing the type to the handler it seems to work to change settings within smartthings but it doesn’t show up at all in Googles devices connected from smartthings. So it has no voice control. I’ve got two of these devices that I’d like to get connected and be able to control them with Google.
I’m fairly new to coding, but I am studying it in school, so any help is much appreciated.
On a much lower priority I’m noticing when I’m changing the temp setting with the remote that came with it that it takes a seemingly long time for the heater to update it’s temperature and to update it back in smartthings. There also seems to be a disconnect from the slide control to set the temperature to the box that I’m assuming only displays the set temperature. Those seem to hold different values for a rather long time. Again though, I’m new to programming and I could be completely wrong in my perception of time…
I’m also noticing that it is reporting values for power usage back to smart things (in watts? Didn’t realize it was that high…) And I’m wondering if it can display consumption in a similar fashion to the the smart plugs that also report power usage.

Thanks again for getting it working in the first place!