Z-Wave Heating Controller UK

This may be a dim question but has anyone had much success in using a boiler switch such as this one or this one with ST? I want to purchase one but want to first make sure it’s compatible (preferably without having to write any code).

Did you have any luck with these?

I didn’t get any answers so am not sure which one to get. Have you tried these or similar yet?

I have the Secure SSR303 Z Wave Boiler Control, was easy to install and after a bit of persuasion hacked the generic thermostat device to make it work as a simple heat/off. Have been able to use with the smart lighting app to turn my boiler on and off to at set times.

@funkyd101 would you post posting your modified DTH please? Save me some time?

Thanks

Most of it is probably redundant as is based on the thermostat device but here is what I have been using for a year or so with no issues

/**

  • 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.

*/
metadata {
definition (name: “Secure boiler reciver”, namespace: “funkyd101”, author: “funkyd101”) {
capability "Actuator"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Thermostat"
capability "Configuration"
capability "Polling"
capability "Sensor"
capability “Switch”

attribute “thermostatFanState”, "string"
command "switchMode"
command "switchFanMode"
command "quickSetCool"
command “quickSetHeat”
// raw string "0 0 0x0800 0 0 0 4 0x72 0x86 0x40 0x25"
fingerprint deviceId: "0x0800"
fingerprint inClusters: “0x72 0x86 0x40 0x25”
}
// simulator metadata
simulator {
status “off” : "command: 4003, payload: 00"
status “heat” : “command: 4003, payload: 01”
//status “cool” : “command: 4003, payload: 02”
//status “auto” : “command: 4003, payload: 03”
//status “emergencyHeat” : “command: 4003, payload: 04”

//status “fanAuto” : “command: 4403, payload: 00”
//status “fanOn” : “command: 4403, payload: 01”
//status “fanCirculate” : “command: 4403, payload: 06”
//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 “cool 72” : “command: 4303, payload: 02 09 48”
//status “cool 76” : “command: 4303, payload: 02 09 4C”
//status “cool 80” : “command: 4303, payload: 02 09 50”
//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"
status “cooling” : “command: 4203, payload: 02"
status “fan only” : “command: 4203, payload: 03"
status “pending heat” : “command: 4203, payload: 04"
status “pending cool” : “command: 4203, payload: 05"
status “vent economizer”: “command: 4203, payload: 06”
// reply messages
reply “2502”: “command: 2503, payload: FF”
}
tiles {
/*
valueTile(“temperature”, “device.temperature”, width: 2, height: 2) {
state(“temperature”, label:’${currentValue}°’,
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”]
]
)
}
/*
multiAttributeTile(name:“switch”, type: “lighting”, width: 6, height: 4, canChangeIcon: true){
tileAttribute (“device.switch”, key: “PRIMARY_CONTROL”) {
attributeState “on”, label:’${name}’, action:“off”, icon:“st.switches.switch.on”, backgroundColor:”#79b821”, nextState:“turningOff"
attributeState “off”, label:’${name}’, action:“heat”, icon:“st.switches.switch.off”, backgroundColor:”#ffffff”, nextState:“turningOn"
attributeState “turningOn”, label:’${name}’, action:“off”, icon:“st.switches.switch.on”, backgroundColor:”#79b821”, nextState:“turningOff"
attributeState “turningOff”, label:’${name}’, action:“heat”, icon:“st.switches.switch.off”, backgroundColor:”#ffffff”, nextState:“turningOn”
}
}
*/
standardTile(“mode”, “device.thermostatMode”, inactiveLabel: false) {
state “off”, label:’${name}’, action:“heat”, nextState:“heat”, icon:“st.Home.home1”
// state “to_heat”, label: “heat”, action:“off”, nextState:“off”, backgroundColor:”#bc2323"
state “heat”, label:’${name}’, action:“off”, nextState:“off”, backgroundColor:”#d04e00",icon:“st.Home.home1”
// state “…”, label: “…”, action:“off”, nextState:“off”
/*state “heat”, label:’${name}’, action:“switchMode”, nextState:“to_cool"
state “cool”, label:’${name}’, action:“switchMode”, nextState:”…“
state “auto”, label:’${name}’, action:“switchMode”, nextState:”…“
state “emergency heat”, label:’${name}’, action:“switchMode”, nextState:”…“
state “to_heat”, label: “heat”, action:“switchMode”, nextState:“to_cool"
state “to_cool”, label: “cool”, action:“switchMode”, nextState:”…“
state “…”, label: “…”, action:“off”, nextState:“off”
*/
}
/*standardTile(“fanMode”, “device.thermostatFanMode”, inactiveLabel: false, decoration: “flat”) {
state “fanAuto”, label:’${name}’, action:“switchFanMode"
state “fanOn”, label:’${name}’, action:“switchFanMode"
state “fanCirculate”, label:’${name}’, action:“switchFanMode”
}
controlTile(“heatSliderControl”, “device.heatingSetpoint”, “slider”, height: 1, width: 2, inactiveLabel: false) {
state “setHeatingSetpoint”, action:“quickSetHeat”, backgroundColor:”#d04e00
}
valueTile(“heatingSetpoint”, “device.heatingSetpoint”, inactiveLabel: false, decoration: “flat”) {
state “heat”, label:’${currentValue}° heat’, backgroundColor:”#ffffff
}
controlTile(“coolSliderControl”, “device.coolingSetpoint”, “slider”, height: 1, width: 2, inactiveLabel: false) {
state “setCoolingSetpoint”, action:“quickSetCool”, backgroundColor: “#1e9cbb
}
valueTile(“coolingSetpoint”, “device.coolingSetpoint”, inactiveLabel: false, decoration: “flat”) {
state “cool”, label:’${currentValue}° cool’, backgroundColor:"#ffffff"
}
*/
standardTile(“refresh”, “device.thermostatMode”, inactiveLabel: false, decoration: “flat”) {
state “default”, action:“polling.poll”, icon:“st.secondary.refresh”
}
standardTile(“configure”, “device.configure”, inactiveLabel: false, decoration: “flat”) {
state “configure”, label:’’, action:“configuration.configure”, icon:“st.secondary.configure”
}
//main “temperature”
//details([“temperature”, “mode”, “fanMode”, “heatSliderControl”, “heatingSetpoint”, “coolSliderControl”, “coolingSetpoint”, “refresh”, “configure”])
main "mode"
details([“mode”,“refresh”, “configure”])
}
}
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”,“coolingSetpoint”,“thermostatMode”]) {
def map2 = [
name: “thermostatSetpoint”,
unit: getTemperatureScale()
]
if (map.name == “thermostatMode”) {
state.lastTriedMode = map.value
if (map.value == “cool”) {
map2.value = device.latestValue(“coolingSetpoint”)
log.info “THERMOSTAT, latest cooling setpoint = ${map2.value}”
}
else {
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” && mode == “heat”) || (map.name == “coolingSetpoint” && mode == “cool”)) {
map2.value = map.value
map2.unit = map.unit
}
}
if (map2.value != null) {
log.debug "THERMOSTAT, adding setpoint event: $map"
result << createEvent(map2)
}
} else if (map.name == “thermostatFanMode” && map.isStateChange) {
state.lastTriedFanMode = map.value
}
log.debug "Parse returned $result"
result
}

// Event Generation
def zwaveEvent(physicalgraph.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;
case 2:
map.name = "coolingSetpoint"
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(physicalgraph.zwave.commands.sensormultilevelv3.SensorMultilevelReport cmd)
{
def map = [:]
if (cmd.sensorType == 1) {
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? “F” : “C”, cmd.precision)
map.unit = getTemperatureScale()
map.name = “temperature”
} else if (cmd.sensorType == 5) {
map.value = cmd.scaledSensorValue
map.unit = "%"
map.name = “humidity”
}
map
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport cmd)
{
def map = [:]
switch (cmd.operatingState) {
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
map.value = "idle"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING:
map.value = "heating"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_COOLING:
map.value = "cooling"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_FAN_ONLY:
map.value = "fan only"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_HEAT:
map.value = "pending heat"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_COOL:
map.value = "pending cool"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_VENT_ECONOMIZER:
map.value = "vent economizer"
break
}
map.name = "thermostatOperatingState"
map
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) {
def map = [name: “thermostatFanState”, unit: “”]
switch (cmd.fanOperatingState) {
case 0:
map.value = "idle"
break
case 1:
map.value = "running"
break
case 2:
map.value = "running high"
break
}
map
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
def map = [:]
switch (cmd.mode) {
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
map.value = "off"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
map.value = "heat"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
map.value = "emergency heat"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
map.value = "cool"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
map.value = "auto"
break
}
map.name = "thermostatMode"
map
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
def map = [:]
switch (cmd.fanMode) {
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
map.value = "fanAuto"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
map.value = "fanOn"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
map.value = "fanCirculate"
break
}
map.name = "thermostatFanMode"
map.displayed = false
map
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
def supportedModes = ""
if(cmd.off) { supportedModes += "off " }
if(cmd.heat) { supportedModes += "heat " }
if(cmd.auxiliaryemergencyHeat) { supportedModes += "emergency heat " }
if(cmd.cool) { supportedModes += "cool " }
if(cmd.auto) { supportedModes += "auto " }
state.supportedModes = supportedModes
}

def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = ""
if(cmd.auto) { supportedFanModes += "fanAuto " }
if(cmd.low) { supportedFanModes += "fanOn " }
if(cmd.circulation) { supportedFanModes += "fanCirculate " }
state.supportedFanModes = supportedFanModes
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
log.debug “Zwave event received: $cmd”
}

def zwaveEvent(physicalgraph.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(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format(),
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format()
], 2300)
}

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

def setHeatingSetpoint(degrees, delay = 30000) {
setHeatingSetpoint(degrees.toDouble(), delay)
}

def setHeatingSetpoint(Double degrees, Integer delay = 30000) {
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 convertedDegrees
if (locationScale == “C” && deviceScaleString == “F”) {
convertedDegrees = celsiusToFahrenheit(degrees)
} else if (locationScale == “F” && deviceScaleString == “C”) {
convertedDegrees = fahrenheitToCelsius(degrees)
} else {
convertedDegrees = degrees
}
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
], delay)
}

def quickSetCool(degrees) {
setCoolingSetpoint(degrees, 1000)
}

def setCoolingSetpoint(degrees, delay = 30000) {
setCoolingSetpoint(degrees.toDouble(), delay)
}

def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
log.trace "setCoolingSetpoint($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 convertedDegrees
if (locationScale == “C” && deviceScaleString == “F”) {
convertedDegrees = celsiusToFahrenheit(degrees)
} else if (locationScale == “F” && deviceScaleString == “C”) {
convertedDegrees = fahrenheitToCelsius(degrees)
} else {
convertedDegrees = degrees
}
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()
], delay)
}

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

def modes() {
//[“off”, “heat”, “cool”, “auto”, “emergency heat”]
[“off”, “heat”]
}

def switchMode() {
def currentMode = device.currentState(“thermostatMode”)?.value
def lastTriedMode = state.lastTriedMode ?: currentMode ?: "off"
def supportedModes = getDataByName(“supportedModes”)
def modeOrder = modes()
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
if (supportedModes?.contains(currentMode)) {
while (!supportedModes.contains(nextMode) && nextMode != “off”) {
nextMode = next(nextMode)
}
}
state.lastTriedMode = nextMode
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[nextMode]).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], 1000)
}

def switchToMode(nextMode) {
def supportedModes = getDataByName(“supportedModes”)
if(supportedModes && !supportedModes.contains(nextMode)) log.warn “thermostat mode ‘$nextMode’ is not supported"
if (nextMode in modes()) {
state.lastTriedMode = nextMode
”$nextMode"()
} else {
log.debug(“no mode method ‘$nextMode’”)
}
}

def switchFanMode() {
def currentMode = device.currentState(“thermostatFanMode”)?.value
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
def supportedModes = getDataByName(“supportedFanModes”) ?: "fanAuto fanOn"
def modeOrder = [“fanAuto”, “fanCirculate”, “fanOn”]
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
while (!supportedModes?.contains(nextMode) && nextMode != “fanAuto”) {
nextMode = next(nextMode)
}
switchToFanMode(nextMode)
}

def switchToFanMode(nextMode) {
def supportedFanModes = getDataByName(“supportedFanModes”)
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode ‘$nextMode’ is not supported"
def returnCommand
if (nextMode == “fanAuto”) {
returnCommand = fanAuto()
} else if (nextMode == “fanOn”) {
returnCommand = fanOn()
} else if (nextMode == “fanCirculate”) {
returnCommand = fanCirculate()
} else {
log.debug(“no fan mode ‘$nextMode’”)
}
if(returnCommand) state.lastTriedFanMode = nextMode
returnCommand
}

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

def getModeMap() { [
“off”: 0,
“heat”: 1,
//“cool”: 2,
//“auto”: 3,
//“emergency heat”: 4
]}

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

def getFanModeMap() { [
“auto”: 0,
“on”: 1,
“circulate”: 6
]}
9
def setThermostatFanMode(String value) {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[value]).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}

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

def on() {
heat()
}

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

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

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

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

def fanOn() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 1).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}

def fanAuto() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 0).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}

def fanCirculate() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 6).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}

private getStandardDelay() {
1000
}

Thanks. I’m using it to control a water recirculation pump.

Out of curiosity do you get any issues where it enters fail safe mode because it hasn’t been paired with a Secure Thermostat?

that’s ok, happy to help.
I haven’t had any issues, with a fail safe mode, no.

1 Like

Bit more help if you have a couple of minutes.

I’m still getting the failsafe issue. To confirm my setup, I have one of these:


Connected directly to ST (no thermostat).

What happens is that I turn it on, after an hour the control enters failsafe mode and turns off. This is as per the documentation shown below.

So, do you not turn it on for more than an hour?

I’ve tried polling the switch as well as sending an on command during the hour but nothing works.

Thanks.

Hmmm, is the same, receiver, and thinking about it yes it does frequently switch off. I didn’t realise this was a failsafe. however as I use it for heating with a virtual thermostat it hasn’t been too much of an issue. We’ll not enough for me to find look for a solution.
Wouldn’t have the first clue how to fix it anyway, if you find a solution let met know.

I assume by polling you mean sending a GET MODE command, if not, try that?

Is there is a parameter that can be set?, or we could write into the device to resend the on command on a loop every hour…

Else Yeh think the, off/on might be the only answer.

Will have a play myself tomorrow.

1 Like

Cards on the table, I’m no coder but that sounds like it makes sense.

I’ve just had a look in CoRE to see if I can “GET MODE” but it’s not available, otherwise I’d setup a loop int there.

Minor point. The receiver expects a command from the thermostat every 45 mins and the host failsafe mode after 60 mins (according to the docs). So, if you have the time to look at putting a GET MODE in the DTH you might want to set the loop for every 45 mins.

Appreciate you looking.

I’m also realising that there a load of logic errors in the piston above. Piston simplified and updated as follows.

I’m monitoring it and will confirm that it goes failsafe after an hour of operation later today.

Hi Paul,

I’m in the same boat as you. Just fitted the SSR303 and it goes into fail safe even though I poll the heck out of it with Pollster. I’m using your DTH from a separate thread which is great.

Besides the fail safe issue, the Smartthings app doesn’t seem to update it’s display with on or off. Do you have that problem too? It would be useful if it had an indicator for fail safe too!

Thanks for the great input you’ve already given on this.

James

Hi James,

I gave up on it in the end and used an Aeotec Smart Switch.

The Secure/Horstmann relies on the Thermostat polling it to prevent it turning off. Shame.