Linear Siren - SHM setting siren to "both" instead of "on"

Hi,
I modified some device type code (see below) that someone started to develop for a Linear Siren. The siren has configuration capability (siren, strobe, or both).
The following code works for controlling the siren manually…everything works. However, when I arm Smart Home Monitor and trigger a sensor, live logging on the Linear alarm shows “Setting alarm to both”, instead of turning the alarm on. However, it does show “sending off” when I disarm SHM.
I suspect that SHM is sending the on command and my device code is using it wrong…but maybe not. Is there a way to look at the app code, or log on the app itself? Otherwise, I can only log my Linear Siren device. My device code is below:

metadata {
definition (name: “Linear Z-Wave Siren”, namespace: “x”, author: “x”) {
capability "Actuator"
capability "Alarm"
capability "Battery"
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Switch"
command "strobe"
command “siren"
command “both”
//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) {
state “both”, label:‘alarm!’, action:‘alarm.siren’, icon:“st.alarm.alarm.alarm”, backgroundColor:”#e86d13"
state “siren”, label:‘siren!’, action:‘alarm.strobe’, icon:“st.alarm.alarm.alarm”, backgroundColor:”#e86d13"
state “strobe”, label:‘strobe!’, action:‘alarm.both’, 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 strobe() {
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 siren() {
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 both() {
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 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 > 5360601000) {
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()
}

Can you tell me what the parse is returning?

I was the original one who tried to help another user. I don’t actually have the device and was never able to get to full fonctionality. I’d guess your issue is the command section

command “strobe”
command “siren”
command “both”

try adding both

command “on”
command “off”

Hi Tim,
Below is the log from the Linear Siren. I started the test with the Siren set to “Strobe” (which does work if I test it using the on/off button in the Things gui).

When SHM is armed, and then I trigger a motion sensor, SHM shows the intruder alert, and the activity shows the “Siren is On”. However, as you can see below, the first log is “Setting alarm to both”.

I then disarm SHM, and clear the alerts/dismiss the alarm. Then the log shows “Sending off” and the parses show up also.

Kevin, thanks for the original code…it was close. I also suspect that area, since “Both” is logging instead of an “On” command. One interesting item I noted in your original help thread: each of the “def strobe” (etc) areas had an on() at end of the definition…but this caused the Linear siren to turn on each time you tried to toggle the function mode, so I removed them.

f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:18 AM: debug Parse returned [Linear Z-Wave Siren switch is off, Linear Z-Wave Siren alarm is both]
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:18 AM: debug createEvents with cmd value {0}, LastAlarmtype: 0
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:18 AM: debug parse(zw device: 16, command: 2003, payload: 00 ) - command is BasicReport(value: 0)
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:16 AM: debug Parse returned [Linear Z-Wave Siren switch is off, Linear Z-Wave Siren alarm is both]
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:16 AM: debug createEvents with cmd value {0}, LastAlarmtype: 0
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:16 AM: debug parse(zw device: 16, command: 2003, payload: 00 ) - command is BasicReport(value: 0)
f58439c1-31f8-4cdc-b384-62c2fae83856 7:53:11 AM: debug sending off
f58439c1-31f8-4cdc-b384-62c2fae83856 7:52:09 AM: debug Setting alarm to both.

Someone else took over the code when I gave up and added those. That definitely didn’t make sense. I think my issue was that I was missing the format() on the end of the zwave commands.

My thought was do you need the on/off in the commands section, but digging in the docs, I guess those are only needed for custom commands

Yeah, I saw that…it was his base that I started with since he claimed to have done some cleanup, but apparently not the right cleanup.

I thought about the commands section also, but dismissed it since on/off does work (with the on/off buttons…that’s how I tested that the configuration commands were working). I also noticed that the Linear siren visually “acks” when a config command is sent. The LED blicks once each time the mode (strobe, siren, or both) is sent. That’s kinda nice and not mentioned in the Linear instruction sheet.

what happens if you use the default z-wave siren DTH?

Good idea…meant to try this.

Bottomline: it appears that nothing is sent to the Linear siren that triggers an “on” state. However, just like my device type, the “off” command gets sent.

Edit: if I go into the “Things” device GUI, selecting the main alarm icon turns the siren/strobe on…and if I click the off button, it turns off. So the siren does understand off/on just fine from the z-wave siren device type…but so does my device type. I’m really getting curious what the SHM app is sending as an “on” message.

Here’s the parse:

f58439c1-31f8-4cdc-b384-62c2fae83856 12:43:42 PM: debug Parse returned [Linear Z-Wave Siren switch is off, Linear Z-Wave Siren alarm is off]
f58439c1-31f8-4cdc-b384-62c2fae83856 12:43:42 PM: debug parse(zw device: 16, command: 2003, payload: 00 )
f58439c1-31f8-4cdc-b384-62c2fae83856 12:43:41 PM: debug Parse returned [Linear Z-Wave Siren switch is off, Linear Z-Wave Siren alarm is off]
f58439c1-31f8-4cdc-b384-62c2fae83856 12:43:41 PM: debug parse(zw device: 16, command: 2003, payload: 00 )
f58439c1-31f8-4cdc-b384-62c2fae83856 12:43:37 PM: debug sending off

hmmmmm ok, can you write into support so we can track this?

Sure, will do it in a few minutes.

Edit: done.

Mike

Interesting update…figured out a workaround:

I tried all the siren device types in Smartthings, and in most cases, continued to get a trigger in the “alarm.both” area when the siren is supposed to come on.

Therefore, I continued to tinker with my device type…under the assumption that Smart Home Monitor app is sending a “alarm.both” command as the “on” command. I deleted the “def siren, def strobe, def both” areas, and created my own commands “setstrobe” “setsiren” “setboth” to send configuration commands to the siren when I toggled through the icon options. This would prevent any standard “strobe, siren, both” commands from interfering with the config. I then put back in “def both”…but only assigned it the function “on()”.

Bingo…it works. I can now configure the siren for any mode, then arm SHM…have an intrusion alert…and the siren turns on in the mode I told it to.

Granted, this is a work around. Smart Home Monitor should really just be sending an “on” command…SHM does send the “off” command…so that part is correct. This code should also work if SHM is updated with just an “on” command.

Here’s the code:

/**
 *  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()
}
1 Like

Sorry for asking a noob question. I click create a new app, click From Code then i copied and pasted your code, click Create and i get this error

No signature of method: script14481720991911909865360.metadata() is applicable for argument types: (script14481720991911909865360$_run_closure1) values: [script14481720991911909865360$_run_closure1@604e149d] Possible solutions: getMetadata(), getState(), setState(java.lang.Object), metaClass(groovy.lang.Closure)

Please help me out. Thank you

1 Like

This is a device type NOT a smart app