Linear Z-wave Siren device type needed

And now I think I see why my device type commands ddin’t work. I was missing the format() at the end of all my zwave commands

Updated working code. I have a support ticket open with Smartthings support on integration with Smart Home Monitor. However, I got it to work with SHM, but it seems like a workaround. SHM sends a “both” command to turn the alarm on, when it really should be sending an “on” command. I created separate commands to config the alarm type, then setup a “def both” to get it to turn on. If Smartthings starts sending just an “on()” message, it should still work ok (I think).

Anyway, here ya go:
PS: Kevin, how can I paste this code in a scrolling window? I’m sure it’s obvious, but I don’t see it.

/**
 *  Linear Zwave Siren v3
 *
 *  Copyright 2015 Kevin Tierney
 *
 *  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.
 *Author: Kevin Tierney
 *  Date: 2015-07-30
 *  Updates by: Mike Wilson
 *  Date: 2015-11-01
 */
metadata {
	definition (name: "Linear Z-Wave Siren v3", namespace: "tierneykev", author: "Kevin Tierney") {
		capability "Actuator"
        capability "Alarm"
        capability "Battery"
        capability "Polling"
        capability "Refresh"
        capability "Sensor"
		capability "Switch"
        command "setstrobe"
        command "setsiren"
        command "setboth"
        //Supported Command Classes
    //0x20-Basic ,0x25-Binary Switch ,0x70-Configuration , 0x72-Manufacturer Specific ,0x86-Version
//        fingerprint inClusters: "0x20,0x25,0x70,0x72,0x86"
         fingerprint deviceId:"0x1000", inClusters: "0x25,0x70,0x72,0x80,0x86"
//         0 0 0x1000 0 0 0 4 0x25 0x70 0x72 0x86
	}
	simulator {
		// reply messages
		reply "2001FF,2002": "command: 2002, payload: FF"
		reply "200100,2002": "command: 2002, payload: 00"
		reply "200121,2002": "command: 2002, payload: 21"
		reply "200142,2002": "command: 2002, payload: 42"
		reply "2001FF,delay 3000,200100,2002": "command: 2002, payload: 00"
	}
    tiles {
	standardTile("alarm", "device.alarm", width: 2, height: 2) {
    log.debug "Adjusting alarm state"
       
        state "both", label:'alarm!', action:"setsiren", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
        state "siren", label:'siren!', action:"setstrobe", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
        state "strobe", label:'strobe!', action:"setboth", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"						
	}
        standardTile("off", "device.alarm", inactiveLabel: false, decoration: "flat") {
 			state "default", label:'Off', action:"off"
        } 
        standardTile("on", "device.alarm", inactiveLabel: false, decoration: "flat") {
 			state "default", label:'On', action:"on"
        } 
        valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { 
			state "battery", label:'${currentValue}% battery', unit:""
		}
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
			state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
		}
       
	main "alarm"
    details(["alarm","off","on","battery","refresh"])
}

preferences {
	input "autoStopTime", "enum", title: "Disarm Time",required:true,displayDuringSetup:true, options: ["30","60","120","Infinite"],default:'30'
}
}
def updated() {
		def autoStopTimeParameter = 0
        if (autoStopTime == '30') {
        	autoStopTimeParameter = 0
        } else if( autoStopTime == '60'){
        	autoStopTimeParameter = 1
        } else if (autoStopTime == '120') {
        	autoStopTimeParameter = 2
        } else if (autoStopTime == 'Infinite') {
        	autoStopTimeParameter = 3
        }
        log.debug "AutoStopTime - ${autoStopTimeParameter}"
	    zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [autoStopTimeParameter])
}
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()



def setstrobe() {
	log.debug "Setting alarm to strobe."
    state.LastAlarmtype = 2
    sendEvent(name: "alarm", value: "strobe")
    zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [2]).format()
     
}
def setsiren() {
    log.debug "Setting alarm to siren."
    state.LastAlarmtype = 1
   sendEvent(name: "alarm", value: "siren")
   zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [1]).format()
     
}
def setboth() {
	log.debug "Setting alarm to both."
    state.LastAlarmtype = 0
    sendEvent(name: "alarm", value: "both")
	zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [0]).format()
 
     
}


def off() {
	log.debug "sending off"
	[
		zwave.basicV1.basicSet(value: 0x00).format(),
		zwave.basicV1.basicGet().format()
	]
}
def on() {
	log.debug "sending on"
	[
		zwave.basicV1.basicSet(value: 0xff).format(),
		zwave.basicV1.basicGet().format()
	]
}

def both() {
	log.debug "sending alarm on via both"
	[
		zwave.basicV1.basicSet(value: 0xff).format(),
		zwave.basicV1.basicGet().format()
	]
}

def parse(String description) {
    def result = null
def cmd = zwave.parse(description)
log.debug "parse($description) - command is $cmd"
if (cmd) {
	result = createEvents(cmd)
}
log.debug "Parse returned ${result?.descriptionText}"
return result
}
def createEvents(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
{
	log.debug "createEvents with cmd value {$cmd.value}, LastAlarmtype: $state.LastAlarmtype"
	def switchValue = cmd.value ? "on" : "off"
	def alarmValue 
	if (state.LastAlarmtype == 0) {
		alarmValue = "both"
	}
	else if (state.LastAlarmtype == 2) {
		alarmValue = "strobe"
	}
	else if (state.LastAlarmtype == 1) {
		alarmValue = "siren"
	}
	else {
		alarmValue = "off"
	}
	[
		createEvent([name: "switch", value: switchValue, type: "digital", displayed: false]),
		createEvent([name: "alarm", value: alarmValue, type: "digital"])
	]
}
def createEvents(physicalgraph.zwave.Command cmd) {
	log.warn "UNEXPECTED COMMAND: $cmd"
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
	def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
	if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) {
		result << response(zwave.batteryV1.batteryGet())
		result << response("delay 1200")
	}
	result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
	result
}
def createEvents(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
	def map = [ name: "battery", unit: "%" ]
	if (cmd.batteryLevel == 0xFF) {
		map.value = 1
		map.descriptionText = "$device.displayName has a low battery"
		map.isStateChange = true
	} else {
		map.value = cmd.batteryLevel
	}
	state.lastbatt = new Date().time
	[createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}
def createEvents(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd)
{
    log.debug "CONFIGURATIONREPORT"
}
def poll() {
	if (secondsPast(state.lastbatt, 36*60*60)) {
		return zwave.batteryV1.batteryGet().format()
	} else {
		return null
	}
}
private Boolean secondsPast(timestamp, seconds) {
	if (!(timestamp instanceof Number)) {
		if (timestamp instanceof Date) {
			timestamp = timestamp.time
		} else if ((timestamp instanceof String) && timestamp.isNumber()) {
			timestamp = timestamp.toLong()
		} else {
			return true
		}
	}
	return (new Date().time - timestamp) > (seconds * 1000)
}
def refresh() {
	log.debug "sending battery refresh command"
	zwave.batteryV1.batteryGet().format()
}
1 Like

Here it is with the scoller. Paste all the code in, then highlight your code and either do Ctrl-K or Click on the </>

It also works if you put your code in github and paste a link to it

/**
* Linear Zwave Siren v3
*
* Copyright 2015 Mike Wilson
*
* 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: "Linear Z-Wave Siren v3", namespace: "miketx", author: "Mike Wilson") {
capability "Actuator"
capability "Alarm"
capability "Battery"
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Switch"
command "setstrobe"
command "setsiren"
command "setboth"
//Supported Command Classes
//0x20-Basic ,0x25-Binary Switch ,0x70-Configuration , 0x72-Manufacturer Specific ,0x86-Version
// fingerprint inClusters: "0x20,0x25,0x70,0x72,0x86"
fingerprint deviceId:"0x1000", inClusters: "0x25,0x70,0x72,0x80,0x86"
// 0 0 0x1000 0 0 0 4 0x25 0x70 0x72 0x86
}
simulator {
// reply messages
reply "2001FF,2002": "command: 2002, payload: FF"
reply "200100,2002": "command: 2002, payload: 00"
reply "200121,2002": "command: 2002, payload: 21"
reply "200142,2002": "command: 2002, payload: 42"
reply "2001FF,delay 3000,200100,2002": "command: 2002, payload: 00"
}
tiles {
standardTile("alarm", "device.alarm", width: 2, height: 2) {
log.debug "Adjusting alarm state"

    state "both", label:'alarm!', action:"setsiren", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
    state "siren", label:'siren!', action:"setstrobe", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
    state "strobe", label:'strobe!', action:"setboth", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"						
}
    standardTile("off", "device.alarm", inactiveLabel: false, decoration: "flat") {
		state "default", label:'Off', action:"off"
    } 
    standardTile("on", "device.alarm", inactiveLabel: false, decoration: "flat") {
		state "default", label:'On', action:"on"
    } 
    valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { 
		state "battery", label:'${currentValue}% battery', unit:""
	}
    standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
		state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
	}

main "alarm"
details(["alarm","off","on","battery","refresh"])
}

preferences {
input "autoStopTime", "enum", title: "Disarm Time",required:true,displayDuringSetup:true, options: ["30","60","120","Infinite"],default:'30'
}
}
def updated() {
def autoStopTimeParameter = 0
if (autoStopTime == '30') {
autoStopTimeParameter = 0
} else if( autoStopTime == '60'){
autoStopTimeParameter = 1
} else if (autoStopTime == '120') {
autoStopTimeParameter = 2
} else if (autoStopTime == 'Infinite') {
autoStopTimeParameter = 3
}
log.debug "AutoStopTime - ${autoStopTimeParameter}"
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [autoStopTimeParameter])
}
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()

def setstrobe() {
log.debug "Setting alarm to strobe."
state.LastAlarmtype = 2
sendEvent(name: "alarm", value: "strobe")
zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [2]).format()

}
def setsiren() {
log.debug "Setting alarm to siren."
state.LastAlarmtype = 1
sendEvent(name: "alarm", value: "siren")
zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [1]).format()

}
def setboth() {
log.debug "Setting alarm to both."
state.LastAlarmtype = 0
sendEvent(name: "alarm", value: "both")
zwave.configurationV1.configurationSet(parameterNumber: 0, size: 1, configurationValue: [0]).format()

}

def off() {
log.debug "sending off"
[
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
]
}
def on() {
log.debug "sending on"
[
zwave.basicV1.basicSet(value: 0xff).format(),
zwave.basicV1.basicGet().format()
]
}

def both() {
log.debug "sending alarm on via both"
[
zwave.basicV1.basicSet(value: 0xff).format(),
zwave.basicV1.basicGet().format()
]
}

def parse(String description) {
def result = null
def cmd = zwave.parse(description)
log.debug "parse($description) - command is $cmd"
if (cmd) {
result = createEvents(cmd)
}
log.debug "Parse returned ${result?.descriptionText}"
return result
}
def createEvents(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
{
log.debug "createEvents with cmd value {$cmd.value}, LastAlarmtype: $state.LastAlarmtype"
def switchValue = cmd.value ? "on" : "off"
def alarmValue 
if (state.LastAlarmtype == 0) {
alarmValue = "both"
}
else if (state.LastAlarmtype == 2) {
alarmValue = "strobe"
}
else if (state.LastAlarmtype == 1) {
alarmValue = "siren"
}
else {
alarmValue = "off"
}
[
createEvent([name: "switch", value: switchValue, type: "digital", displayed: false]),
createEvent([name: "alarm", value: alarmValue, type: "digital"])
]
}
def createEvents(physicalgraph.zwave.Command cmd) {
log.warn "UNEXPECTED COMMAND: $cmd"
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) {
result << response(zwave.batteryV1.batteryGet())
result << response("delay 1200")
}
result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
result
}
def createEvents(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "$device.displayName has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
state.lastbatt = new Date().time
[createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}
def createEvents(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd)
{
log.debug "CONFIGURATIONREPORT"
}
def poll() {
if (secondsPast(state.lastbatt, 36*60*60)) {
return zwave.batteryV1.batteryGet().format()
} else {
return null
}
}
private Boolean secondsPast(timestamp, seconds) {
if (!(timestamp instanceof Number)) {
if (timestamp instanceof Date) {
timestamp = timestamp.time
} else if ((timestamp instanceof String) && timestamp.isNumber()) {
timestamp = timestamp.toLong()
} else {
return true
}
}
return (new Date().time - timestamp) > (seconds * 1000)
}
def refresh() {
log.debug "sending battery refresh command"
zwave.batteryV1.batteryGet().format()
}
3 Likes

Cool…thanks Kevin! I fixed my post above so it wouldn’t take up so much space!

I just updated device type. I can choose alert ( strobe, siren,alarm) and they display properly in app and api, but regardless of which is chosen both siren and strobe activate when triggered :frowning:

Did you use the latest code I posted? I just did a quick test again and everything functions as it should, including with SHM. After you set the alarm type, did you try it with the on/off buttons and did that work?

My Linear siren is model ZM1601US (comes in the GoControl kit…battery operated model (not AC model, which is Linear WA105DBZ-1, but both support the same configuration commands and function the same, per the instruction sheet).

Yes, I copied the code posted just above this. On/off button work ( that’s how I tested the different modes ) there was a delay. When I selected strobe, the strobe flashed about 6 times , then the siren kicked in. In siren mode,the siren started sounding a couple seconds before the strobe activated. In alarm mode both siren and strobe start simultaneously.
Yes I’m using the battery powered one from the HD GoControl kit.

Interesting. So when you change the mode, the siren goes off automatically? I’m not sure how that would happen. When I change modes, the siren LED just blinks once to acknowledge the change and stays quiet. It doesn’t activate unless the “on” button is pushed, or Smart Home Monitor is armed and an intrusion alert is triggered.

What does LIve Logging show logging when it turns on?

No not automatically.
I meant after I switch modes and then hit the on button. So if I select strobe, then trigger it, the strobe will flash for a few seconds, before the siren will sound. If I select siren and click on, the siren will sound for a few second before the strobe flashes. If I select alarm they both start simultaneously when I pressed on .

However, whatever it was fixed itself overnight. I just put it through its paces to get you the logs and everything worked perfectly. Now to figure out how to select the separate states for individual devices.

Interesting (before and after).

“separate states for individual devices”…are you still talking about the siren, or something else?

Still talking about siren. I haven’t played with it, but would like to set it something like strobe only if freezer door left open, but have siren go off for freeze or moisture under sink warning. From what I see you can set device only to do the same for every alert. But as I said I haven’t really dug around yet, maybe that changed overnight too :wink:

Yeah, you’d need access to the app to send different config commands to the siren, and then trigger it. Or create/modify an existing app.

Just buy another kit with another siren. Use one for simple alerts like freezer open and one for urgent alarms like leaking sink or freezing basement . :smile:

Yup, that too. I actually bought two GoControl kits because I needed 6 open/close sensors to wire into my old alarm system wiring (the GoControl 5 piece kit has 3, plus 1 motion ,and 1 siren. The motion and door sensors are Ecolink brand, and the siren is Linear). Since I needed a siren, it was the best deal…plus I have an extra siren.

Me too, still have the extra siren, hadn’t decided what to do with it yet. Well looks like I now have a use. Set one on strobe only for the minor things and leave the other on alarm for the major, need my attention now things.

Is this the best version. I just got the gocontrol kit too. Got a zwave switch for the siren.

Just to follow up here, when you write a device type, you should be including all parts of the capabilities into the device. In this case we spec out “alarm” to include the both command. So, this should be included in any device type that has the alarm capability. This way a smart app developer does not need to worry if you did or did not include the full spec of the capability.

Makes sense Tim. The current device type I wrote does still have “both” in it. The Linear siren works differently than other sirens on the market, which accept commands like “both”, “siren”, “strobe”, whereas Linear expects the alarm state to be set via the configuration command, and then the Linear siren just behaves like a switch (off or on).

Yeah, just wanted to clarify why we send “both” and not “on”. In this case you would just write the device type to do the expected action in on it doesn’t really support. Since the linear siren behaves as on off, you would just setup the both command to do the on/off action.

Another scenario for instance would be a media player. Let’s say you had a device that didn’t have a “pause” function but had a “stop” function. Because pause is part of the spec for music player You would just write in a pause function that would send the stop command because that makes the most sense.

Yup…exactly what I did!

1 Like