GE/Jasco Portable Smart Motion Sensor

Would someone mind looking at this ST driver I would like to port to Hubitat? I've tried changing the physicalgraph to hubitat and find that the driver works fine, but the parameter configuration doesn't seem to work.

https://raw.githubusercontent.com/jwillaz/SmartThingsPublic/6c47abe91b26540c8137460c8982abfa3bdfc3e8/devicetypes/smartthings/ge-portable-smart-motion-sensor.src/ge-portable-smart-motion-sensor.groovy

Thanks!

@stephack or @mike.maxwell or any other helpful souls mind taking a look at the above ST driver to see what needs to be modified to get the parameter settings to work?

I have the states “active/inactive” working fine by changing physicalgraph to hubitat, but I REALLY need to be able to adjust parameter 18 in order to make this device usable in RM.

I would HUGELY appreciate any assistance with this!

Edit: In a perfect world, I would also love to know what I have to tweak to get hubitat to recognize the device properly during pairing.

Manufacturer:0063Product Name:DeviceModel Number:Unknown Part NumberdeviceTypeId:12
nodeId:71
deviceId:3133
manufacturer:0063
deviceType:4953
inClusters:0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x80,0x30,0x70,0x7A,0x5A
outClusters:null

Change this form:

zwave.configurationV1.configurationSet(configurationValue: [parameterEighteen], parameterNumber: 18, size: 1).format(),

To this:

zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterEighteen, parameterNumber: 18, size: 1).format(),

Also for clarity add return before the delay between.

Thanks Mike!

Just to make sure I understand you last comment:

original:

def configure() {
** log.debug(“Adjusting parameters…”)**
** delayBetween([**

new:

def configure() {
** log.debug(“Adjusting parameters…”)**
** return delayBetween([**

I think I failed somewhere, doesn’t seem to be working?

def configure() {
log.debug(“Adjusting parameters…”)
return delayBetween([
zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterSix, parameterNumber: 6, size: 1).format(),
zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterThirteen, parameterNumber: 13, size: 1).format(),
zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterEighteen, parameterNumber: 18, size: 1).format(),
zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterTwenty, parameterNumber: 20, size: 1).format(),
zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterTwentyEight, parameterNumber: 28, size: 1).format()
], 500)
}

BINGO

I think I fixed it by “tweaking” the fingerprint line to:

fingerprint deviceId: “3133”, inClusters: “0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x80,0x30,0x70,0x7A,0x5A”, outClusters:"", mfr: “0063”, prod: “4953”, deviceJoinName: “GE Portable Smart Motion Sensor”

Device is now detected as “GE Portable Smart Motion Sensor” upon pairing!

I had assumed that when you switched drivers that you clicked configure in the driver details, not the case?

This seems to be a consistent missed step in setting up devices. Could it be called in code whenever a driver is changed for a device instead of a manual step?

1 Like

that would fix it for zigbee and line powered zwave devices, but not zwave battery devices.
So in the end, the only sure fire way to swap drivers manually is to make sure they are awake, hit configure, and then save in the driver details.

There is no configure option in my driver details.

I think you might have to add the following to your capability section near the top
capability "Configure"

2 Likes

@mike.maxwell Here is the "ported" code for these devices that I have currently working with hubitat. Thought you might want to take a look to see if there is something specific you would need to do to make it work with the "generic" z-wave driver or if you would like I could mail (I have several I'm not using at this time) one of these to you if you wanted to make a "system" driver using a real sample.

/**
 *
 *  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.
 *
 *  GE Portable Smart Motion Sensor adapted from Generic Z-Wave Motion Sensor
 *
 *  Credit to smartthings jwillaz for the original smartthings adaption.
 */

metadata {
	definition (name: "GE Portable Smart Motion Sensor", namespace: "hubitat", author: "halfrican.ak", ocfDeviceType: "x.com.st.d.sensor.motion") {
		capability "Motion Sensor"
		capability "Sensor"
		capability "Battery"
		capability "Health Check"
        capability "Configuration"

		fingerprint deviceId: "3133", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x80,0x30,0x70,0x7A,0x5A", outClusters:"", mfr: "0063", prod: "4953", deviceJoinName: "GE Portable Smart Motion Sensor USB"
		fingerprint deviceId: "3133", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x70,0x7A,0x5A", outClusters:"", mfr: "0063", prod: "4953", deviceJoinName: "GE Portable Smart Motion Sensor Battery"
    }

	
        preferences {
        input "parameterSix", "number", title: "Enable/Disable PIR Sensor: default=1, 0=Disabled, 1=Enabled",  defaultValue: 1, range: "0..1", required: false, displayDuringSetup: true
        input "parameterThirteen", "number", title: "PIR Sensitivity: default=3, 1=Low Sensitivity, 2=Medium Sensitivity, 3=High Sensitivity",  defaultValue: 3, range: "1..3", required: false, displayDuringSetup: true
        input "parameterEighteen", "number", title: "PIR Timeout Duration (minutes): default=1, 1-60",  defaultValue: 1, range: "1..60", required: false, displayDuringSetup: true
        input "parameterTwenty", "number", title: "Basic Set, Notification and Basic Report: default=1, 1=Notification, 2=Basic Set, 3=Basic Report",  defaultValue: 1, range: "1..3", required: false, displayDuringSetup: true
        input "parameterTwentyEight", "number", title: "Enable/Disable LED Flash Indicator: default=1, 0=Disable, 1=Enable",  defaultValue: 1, range: "0..1", required: false, displayDuringSetup: true
	}

	
}

def installed() {
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
	sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}

def updated() {
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
	sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
        response(configure())
}

private getCommandClassVersions() {
	[0x20: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1]
}

def parse(String description) {
	def result = null
	if (description.startsWith("Err")) {
	    result = createEvent(descriptionText:description)
	} else {
		def cmd = zwave.parse(description, commandClassVersions)
		if (cmd) {
			result = zwaveEvent(cmd)
		} else {
			result = createEvent(value: description, descriptionText: description, isStateChange: false)
		}
	}
	return result
}

def sensorValueEvent(value) {
	if (value) {
		createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion")
	} else {
		createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped")
	}
}

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd)
{
	sensorValueEvent(cmd.value)
}

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicSet cmd)
{
	sensorValueEvent(cmd.value)
}

def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd)
{
	sensorValueEvent(cmd.value)
}

def zwaveEvent(hubitat.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd)
{
	sensorValueEvent(cmd.sensorValue)
}

def zwaveEvent(hubitat.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
{
	sensorValueEvent(cmd.sensorState)
}

def zwaveEvent(hubitat.zwave.commands.notificationv3.NotificationReport cmd)
{
	def result = []
	if (cmd.notificationType == 0x07) {
		if (cmd.v1AlarmType == 0x07) {  // special case for nonstandard messages from Monoprice ensors
			result << sensorValueEvent(cmd.v1AlarmLevel)
		} else if (cmd.event == 0x01 || cmd.event == 0x02 || cmd.event == 0x07 || cmd.event == 0x08) {
			result << sensorValueEvent(1)
		} else if (cmd.event == 0x00) {
			result << sensorValueEvent(0)
		} else if (cmd.event == 0x03) {
			result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName covering was removed", isStateChange: true)
			result << response(zwave.batteryV1.batteryGet())
		} else if (cmd.event == 0x05 || cmd.event == 0x06) {
			result << createEvent(descriptionText: "$device.displayName detected glass breakage", isStateChange: true)
		}
	} else if (cmd.notificationType) {
		def text = "Notification $cmd.notificationType: event ${([cmd.event] + cmd.eventParameter).join(", ")}"
		result << createEvent(name: "notification$cmd.notificationType", value: "$cmd.event", descriptionText: text, isStateChange: true, displayed: false)
	} else {
		def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive"
		result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, isStateChange: true, displayed: false)
	}
	result
}

def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
	def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]

	if (state.MSR == "011A-0601-0901" && device.currentState('motion') == null) {  // Enerwave motion doesn't always get the associationSet that the hub sends on join
		result << response(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
	}
	if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) {
		result << response(zwave.batteryV1.batteryGet())
	} else {
		result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
	}
	result
}

def zwaveEvent(hubitat.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.lastbat = new Date().time
	[createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}

def zwaveEvent(hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd)
{
	def map = [ displayed: true, value: cmd.scaledSensorValue.toString() ]
	switch (cmd.sensorType) {
		case 1:
			map.name = "temperature"
			map.unit = cmd.scale == 1 ? "F" : "C"
			break;
		case 3:
			map.name = "illuminance"
			map.value = cmd.scaledSensorValue.toInteger().toString()
			map.unit = "lux"
			break;
		case 5:
			map.name = "humidity"
			map.value = cmd.scaledSensorValue.toInteger().toString()
			map.unit = cmd.scale == 0 ? "%" : ""
			break;
		case 0x1E:
			map.name = "loudness"
			map.unit = cmd.scale == 1 ? "dBA" : "dB"
			break;
	}
	createEvent(map)
}

def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
	def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions)
	// log.debug "encapsulated: $encapsulatedCommand"
	if (encapsulatedCommand) {
		state.sec = 1
		zwaveEvent(encapsulatedCommand)
	}
}

def zwaveEvent(hubitat.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
	// def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions)
	def version = commandClassVersions[cmd.commandClass as Integer]
	def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
	def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
	if (encapsulatedCommand) {
		return zwaveEvent(encapsulatedCommand)
	}
}

def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	def result = null
	def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions)
	log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}"
	if (encapsulatedCommand) {
		result = zwaveEvent(encapsulatedCommand)
	}
	result
}

def zwaveEvent(hubitat.zwave.commands.multicmdv1.MultiCmdEncap cmd) {
	log.debug "MultiCmd with $numberOfCommands inner commands"
	cmd.encapsulatedCommands(commandClassVersions).collect { encapsulatedCommand ->
		zwaveEvent(encapsulatedCommand)
	}.flatten()
}

def zwaveEvent(hubitat.zwave.Command cmd) {
	createEvent(descriptionText: "$device.displayName: $cmd", displayed: false)
}

def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
	def result = []

	def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
	log.debug "msr: $msr"
	updateDataValue("MSR", msr)

	result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
	result
}

def configure() {
	log.debug("Adjusting parameters...")
    return delayBetween([
        zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterSix, parameterNumber: 6, size: 1).format(),
        zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterThirteen, parameterNumber: 13, size: 1).format(),
        zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterEighteen, parameterNumber: 18, size: 1).format(),
        zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterTwenty, parameterNumber: 20, size: 1).format(),
        zwave.configurationV1.configurationSet(scaledConfigurationValue: parameterTwentyEight, parameterNumber: 28, size: 1).format()
    ], 500)
}
2 Likes

Thanks! I was able to set PIR Timeout Duration to 255 with this, for super fast response times. I was having trouble getting my own attempted port to accept parameter 18. But don't forget to add to your metadata

capability "Configuration"

1 Like

If i remember correctly, the 255 setting may not "stick", I think it resets after 10 min. If not, that would be awesome, please let us know.

1 Like

Oh you're right. Checking on it later, looks like it didn't stick. Oh well!

You could schedule the 'Configure' routine to be called periodically, assuming it doesn't interfere with normal operations. You could simply add 'capability "Refresh"' to the driver, and then within the refresh() function, simply call configure(). Then, in rule machine, set up a repeating 10 minute rule to call refresh() on the device.

I don't have one of these GE Smart Motion Sensors, so I have no first hand experience with what ramifications this might have.

Just an idea! :slight_smile:

Thanks for this! I just ported over from Wink and was having a lot of trouble getting my motion sensors to work. I copied and pasted your code and it worked like a charm.

This was hard to find and get working for a pseudo-dev, like me (I only play one on tv). Since you did all the hard work, It would be really cool if you shared it in the Codeshare forum for everyone else - Code Share - Hubitat.

I'm coming from Wink also and having same issues where can I find the code? Also, how do you use it as a driver? Sorry, newbie to Hibitat. Thanks?

Just installed this. Thanks

Unfortunately it's not working on my c7 hub.