Connecting Philio tech PST02-B

Hello all,

I received a Philiotech multisensor today : (PST02-B http://www.philio-tech.com/products_sensors.htm ) and for some reason I can’t get it to work properly, Automatically it connects as a door/window sensor, but I’d like to use it as a lux sensor… Any Idea’s as to how to get this working the way I want?

Any advice is greatly appreciated!

Regards,

Michiel

@Michiel_Brederode, these aren’t on the official list of supported devices, so you’ll need a custom device type. Do a quick search and you’ll find a couple written by community members that work perfectly. I have the older Philio psm-01 sensors working this way.

Thanks john will do!

1 Like

after setting up my PST 02 as a PSM02 I get these errors:

60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:43: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:43: debug PSM02: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 2, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:43: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:43: debug PSM02: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 2, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:42: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:42: debug PSM02: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 2, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:38: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:37: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:36: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:31: debug PSM02: configure() called
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:31: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:30: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:30: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:23: debug PSM02: configure() called
60344fd9-6968-43eb-9b79-87d3a4f45e24 23:37:23: debug PSM02: Updated with settings: [:]

I’m quite a newbie with ST and domotics all together but maybe someone can help me out in getting this to work. I’m mostly interested in the light and sensors of this device

Hi @Michiel_Brederode, What device type did you find to use? Can you give me a link to it?

sorry for the late reply john. I’m using a code from the PSM02 door sensor:

/*

  • Philio PSM02 4-in-1 Multi Sensor Device Type
  • Based on My PSM01 Sensor created by SmartThings/Paul Spee
  • which is based on SmartThings’ Aeon Multi Sensor Reference Device Type
    */

metadata {

definition (name: "Philio PHI_PSM02 Sensor", namespace: "eyeonall", author: "AJ") {
	capability "Contact Sensor"
    capability "Motion Sensor"
	capability "Temperature Measurement"
	capability "Illuminance Measurement"
	capability "Configuration"
	capability "Sensor"
	capability "Battery"
    capability "Refresh"
	capability "Polling"
	fingerprint deviceId: "0x2001", inClusters: "0x80,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0xEF,0x20"
    
}

tiles {

    
	standardTile("contact", "device.contact", width: 2, height: 2) {
		state "closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
		state "open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
	}

	standardTile("motion", "device.motion", width: 2, height: 2) {
		state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
		state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
	}
   
   valueTile("temperature", "device.temperature", inactiveLabel: false) {
		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"]
		]
	}

	valueTile("illuminance", "device.illuminance", inactiveLabel: false) {
		state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
	}
    
	valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
		state "battery", label:'${currentValue}% battery', unit:""
	}
    
	standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
		state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
	}

	standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
		state "default", action:"polling.poll", icon:"st.secondary.refresh"
	}

	main(["contact", "motion", "temperature", "illuminance"])
	details(["contact", "motion", "temperature", "illuminance", "battery", "configure", "refresh"])
	}

	preferences {
		input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
		input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
	}

}

preferences {
}

def installed() {
log.debug "PSM02: Installed with settings: ${settings}"
configure()
}

def updated() {
log.debug "PSM02: Updated with settings: ${settings}"
configure()

}

// parse() with a Map argument is called after a sendEvent(device)
// In this case, we are receiving an event from the PSM01 Helper App to generate a “inactive” event
def parse(Map evt){
// log.debug "Parse(Map) called with map ${evt}"
def result = [];
if (evt)
result << evt;
//log.debug "Parse(Map) returned ${result}"
def statusTextmsg = ""
statusTextmsg = "Door is ${device.currentState(‘contact’).value}, temp is ${device.currentState(‘temperature’).value}°, and illuminance is ${device.currentState(‘illuminance’).value} LUX."
sendEvent(“name”:“statusText”, “value”:statusTextmsg)
//log.debug statusTextmsg

return result

}

// Parse incoming device messages to generate events
def parse(String description)
{
//log.debug "PSM02 Parse called with ${description}"
def result = []
def cmd = zwave.parse(description, [0x20: 1, 0x30: 2, 0x31: 5, 0x70: 1, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1])
//log.debug "PSM02 Parsed CMD: ${cmd.toString()}"
if (cmd) {
if( cmd.CMD == “8407” ) { result << new physicalgraph.device.HubAction(zwave.wakeUpV2.wakeUpNoMoreInformation().format()) }
def evt = zwaveEvent(cmd)
result << createEvent(evt)
}
def statusTextmsg = ""
statusTextmsg = "Door is ${device.currentState(‘contact’).value}, temp is ${device.currentState(‘temperature’).value}°, and illuminance is ${device.currentState(‘illuminance’).value} LUX."
sendEvent(“name”:“statusText”, “value”:statusTextmsg)
//log.debug statusTextmsg
//log.debug "PSM02 Parse returned ${result}"
return result
}

// Event Generation
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
//log.debug “PSM02: WakeUpNotification ${cmd.toString()}}”

[descriptionText: "${device.displayName} woke up", isStateChange: false]

}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd)
{
//log.debug "PSM02: SensorMultilevel ${cmd.toString()}"
def map = [:]
switch (cmd.sensorType) {
case 1:
// temperature
def cmdScale = cmd.scale == 1 ? “F” : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
if (tempOffset) {
def offset = tempOffset as int
def v = map.value as int
map.value = v + offset
}
//log.debug "Adjusted temp value ${map.value}"
break;
case 3:
// luminance
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
map.name = "illuminance"
break;
}
//map
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
//log.debug "PSM02: BatteryReport ${cmd.toString()}}"
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel > 0 ? cmd.batteryLevel.toString() : 1
map.unit = "%"
map.displayed = false
//map
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) {
log.debug "PSM02: SensorBinaryReport ${cmd.toString()}}"
def map = [:]
switch (cmd.sensorType) {
case 10: // contact sensor
map.name = "contact"
log.debug "PSM02 cmd.sensorValue: ${cmd.sensorValue}"
if (cmd.sensorValue.toInteger() > 0 ) {
//log.debug "PSM02 DOOR OPEN"
map.value = "open"
map.descriptionText = “$device.displayName is open”
} else {
//log.debug "PSM02 DOOR CLOSED"
map.value = "closed"
map.descriptionText = “$device.displayName is closed”
}
break;
case 12: // motion sensor
map.name = "motion"
log.debug "PSM02 cmd.sensorValue: ${cmd.sensorValue}"
if (cmd.sensorValue.toInteger() > 0 ) {
//log.debug "PSM02 Motion Detected"
map.value = "active"
map.descriptionText = “$device.displayName is active”
} else {
//log.debug "PSM02 No Motion"
map.value = "inactive"
map.descriptionText = “$device.displayName no motion”
}
map.isStateChange = true
break;
}
//map
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug “PSM02: Catchall reached for cmd: ${cmd.toString()}}”
[:]
}

def configure() {
log.debug “PSM02: configure() called”

delayBetween([
	
    //1 tick = 30 minutes
    zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: 70).format(), // PIR Sensitivity 1-100
    zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 3).format(), // PIR Redetect Interval. Applies only if in security mode
	zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 1).format(), // Auto report Battery time 1-127, default 12
	zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: 2).format(), // Auto report Door/Window state time 1-127, default 12
	zwave.configurationV1.configurationSet(parameterNumber: 12, size: 1, scaledConfigurationValue: 2).format(), // Auto report Illumination time 1-127, default 12
    zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 2).format(), // Auto report Temperature time 1-127, default 12
    zwave.configurationV1.configurationSet(parameterNumber: 7, size: 1, scaledConfigurationValue: 22).format(),
    zwave.wakeUpV1.wakeUpIntervalSet(seconds: 1 * 3600, nodeid:zwaveHubNodeId).format(),						// Wake up every hour

])

}

1e7bc07e-0e81-4dee-ae8e-5589c2e76bb1 20:08:07: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
1e7bc07e-0e81-4dee-ae8e-5589c2e76bb1 20:08:07: debug PSM02: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 53, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}
1e7bc07e-0e81-4dee-ae8e-5589c2e76bb1 20:08:06: error java.lang.NullPointerException: Cannot get property ‘value’ on null object @ line 120
1e7bc07e-0e81-4dee-ae8e-5589c2e76bb1 20:08:06: debug PSM02: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 53, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}

@Michiel_Brederode, cool thanks.

I found the original source code that you mentioned above here:

https://raw.githubusercontent.com/eyeonall/SmartThings-PSM02/master/Philio%20PSM02%20Device%20Type%20Handler.groovy

While your device doesn’t have the open/close sensor (you have the 3-in-1), this should technically still work. I would recommend removing the code that isn’t needed at some point.

I created a device type using the code from that link to see what line 120 looks like because what you posted doesn’t contain line numbers.

To me, that line should not be generating that error. I would recommend replacing all the code you currently have with what is in the link and try again, just to be safe. It’s like something is missing from your code, so let’s start with a refresh if you don’t mind.

EDIT:

I quickly came up with a device type for you to try that removes the contact sensor. Feel free to give this one a try as well. Since I don’t have an actual device to test with, I can’t be sure this works (but it should):

https://raw.githubusercontent.com/constjs/SmartThings-Devices/master/philio_pst02-b_sensor.device.groovy

thanks for the help @johnconstantelo!

It does something, but still won’t register battery, temp, lux or movement…

this is what the log says…

Clear
2143c022-246c-4da5-9e4d-f1bd145a0d0d 21:32:24: debug Parse returned [[isStateChange:false, displayed:false, linkText:test]]
2143c022-246c-4da5-9e4d-f1bd145a0d0d 21:32:24: debug PST02-B: Catchall reached for cmd: SecurityMessageEncapsulation(commandByte: [4, 3, 128, 3, 100, 9, 113, 5, 0, 0, 0, 255, 7, 8, 0, 5, 49, 5, 3, 1, 2, 6, 49, 5], commandClassIdentifier: 143, commandIdentifier: 1, reserved13: 0, secondFrame: false, sequenceCounter: 1, sequenced: true)}
2143c022-246c-4da5-9e4d-f1bd145a0d0d 21:32:24: debug Parse called with zw device: 0D, command: 98C1, payload: 11 8F 01 04 03 80 03 64 09 71 05 00 00 00 FF 07 08 00 05 31 05 03 01 02 06 31 05
2143c022-246c-4da5-9e4d-f1bd145a0d0d 21:32:13: debug Parse returned [[isStateChange:false, displayed:false, linkText:test]]

Try this one. It works with Devolo Motion Sensor MT02647. Perhaps somebody has the ability to clean the code. It`s from the AEON Multisensor 6.

/**

  • 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: “Devolo Motion Sensor MT02647”, namespace: “smartthings/timecrash”, author: “SmartThings”) {
capability “Motion Sensor”
capability “Temperature Measurement”
capability “Illuminance Measurement”
capability “Configuration”
capability “Sensor”
capability “Battery”

  attribute "tamper", "enum", ["detected", "clear"]
  attribute "batteryStatus", "string"
  attribute "powerSupply", "enum", ["USB Cable", "Battery"]
  fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"

}

simulator {
status “no motion” : “command: 9881, payload: 00300300”
status “motion” : “command: 9881, payload: 003003FF”

  for (int i = 0; i <= 100; i += 20) {
  	status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
  		new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
  			scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1)
  		).incomingMessage()
  }
  for (int i in [0, 20, 89, 100, 200, 500, 1000]) {
  	status "illuminance ${i} lux":  new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
  		new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(scaledSensorValue: i, sensorType: 3)
  	).incomingMessage()
  }
  for (int i in [0, 5, 10, 15, 50, 99, 100]) {
  	status "battery ${i}%":  new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
  		new physicalgraph.zwave.Zwave().batteryV1.batteryReport(batteryLevel: i)
  	).incomingMessage()
  }
  status "low battery alert":  new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
  	new physicalgraph.zwave.Zwave().batteryV1.batteryReport(batteryLevel: 255)
  ).incomingMessage()
  status "wake up" : "command: 8407, payload: "

}

preferences {
input description: “Please consult AEOTEC MULTISENSOR 6 operating manual for advanced setting options. You can skip this configuration to use default settings”,
title: “Advanced Configuration”, displayDuringSetup: true, type: “paragraph”, element: “paragraph”

  input "motionDelayTime", "enum", title: "Motion Sensor Delay Time",
  		options: ["20 seconds", "40 seconds", "1 minute", "2 minutes", "3 minutes", "4 minutes"], defaultValue: "${motionDelayTime}", displayDuringSetup: true
  input "motionSensitivity", "enum", title: "Motion Sensor Sensitivity", options: ["normal","maximum","minimum"], defaultValue: "${motionSensitivity}", displayDuringSetup: true
  input "reportInterval", "enum", title: "Sensors Report Interval",
  		options: ["8 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${reportInterval}", displayDuringSetup: true

}

tiles(scale: 2) {
multiAttributeTile(name:“motion”, type: “generic”, width: 6, height: 4){
tileAttribute (“device.motion”, key: “PRIMARY_CONTROL”) {
attributeState “active”, label:‘motion’, icon:“st.motion.motion.active”, backgroundColor:“#53a7c0
attributeState “inactive”, label:‘no motion’, icon:“st.motion.motion.inactive”, backgroundColor:“#ffffff
}
}
valueTile(“temperature”, “device.temperature”, inactiveLabel: false, width: 2, height: 2) {
state “temperature”, label:‘${currentValue}°’,
backgroundColors:[
[value: 32, color: “#153591”],
[value: 44, color: “#1e9cbb”],
[value: 59, color: “#90d2a7”],
[value: 74, color: “#44b621”],
[value: 84, color: “#f1d801”],
[value: 92, color: “#d04e00”],
[value: 98, color: “#bc2323”]
]
}

  valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
  	state "illuminance", label:'${currentValue} ${unit}', unit:"lux"
  }
  valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
  	state "battery", label:'${currentValue}% battery', unit:""
  }
  valueTile("batteryStatus", "device.batteryStatus", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
  	state "batteryStatus", label:'${currentValue}', unit:""
  }
  valueTile("powerSupply", "device.powerSupply", height: 2, width: 2, decoration: "flat") {
  	state "powerSupply", label:'${currentValue} powered', backgroundColor:"#ffffff"
  }
  main(["motion", "temperature", "illuminance"])
  details(["motion", "temperature", "illuminance", "batteryStatus"])

}
}

def updated() {
log.debug “Updated with settings: ${settings}”
log.debug “${device.displayName} is now ${device.latestValue(“powerSupply”)}”

if (device.latestValue(“powerSupply”) == “USB Cable”) { //case1: USB powered
response(configure())
} else if (device.latestValue(“powerSupply”) == “Battery”) { //case2: battery powered
// setConfigured(“false”) is used by WakeUpNotification
setConfigured(“false”) //wait until the next time device wakeup to send configure command after user change preference
} else { //case3: power source is not identified, ask user to properly pair the sensor again
log.warn “power source is not identified, check it sensor is powered by USB, if so > configure()”
def request =
request << zwave.configurationV1.configurationGet(parameterNumber: 101)
response(commands(request))
}
}

def parse(String description) {
log.debug “parse() >> description: $description”
def result = null
if (description.startsWith(“Err 106”)) {
log.debug “parse() >> Err 106”
result = createEvent( name: “secureInclusion”, value: “failed”, isStateChange: true,
descriptionText: “This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.”)
} else if (description != “updated”) {
log.debug “parse() >> zwave.parse(description)”
def cmd = zwave.parse(description, [0x31: 5, 0x30: 2, 0x84: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
}
log.debug “After zwaveEvent(cmd) >> Parsed ‘${description}’ to ${result.inspect()}”
return result
}

//this notification will be sent only when device is battery powered
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def result = [createEvent(descriptionText: “${device.displayName} woke up”, isStateChange: false)]
def cmds =
if (!isConfigured()) {
log.debug(“late configure”)
result << response(configure())
} else {
log.debug(“Device has been configured sending >> wakeUpNoMoreInformation()”)
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
result << response(cmds)
}
result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x30: 2, 0x84: 1])
state.sec = 1
log.debug “encapsulated: ${encapsulatedCommand}”
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
} else {
log.warn “Unable to extract encapsulated cmd from $cmd”
createEvent(descriptionText: cmd.toString())
}
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
log.info “Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd”
state.sec = 1
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.NetworkKeyVerify cmd) {
state.sec = 1
log.info “Executing zwaveEvent 98 (SecurityV1): 07 (NetworkKeyVerify) with cmd: $cmd (node is securely included)”
def result = [createEvent(name:“secureInclusion”, value:“success”, descriptionText:“Secure inclusion was successful”, isStateChange: true)]
result
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.info “Executing zwaveEvent 72 (ManufacturerSpecificV2) : 05 (ManufacturerSpecificReport) with cmd: $cmd”
log.debug “manufacturerId: ${cmd.manufacturerId}”
log.debug “manufacturerName: ${cmd.manufacturerName}”
log.debug “productId: ${cmd.productId}”
log.debug “productTypeId: ${cmd.productTypeId}”
def msr = String.format(“%04X-%04X-%04X”, cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue(“MSR”, msr)
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def result =
def map = [ name: “battery”, unit: “%” ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = “${device.displayName} battery is low”
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
state.lastbatt = now()
result << createEvent(map)
if (device.latestValue(“powerSupply”) != “USB Cable”){
result << createEvent(name: “batteryStatus”, value: “${map.value} % battery”, displayed: false)
}
result
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
def map = [:]
switch (cmd.sensorType) {
case 1:
map.name = “temperature”
def cmdScale = cmd.scale == 1 ? “F” : “C”
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
break
case 3:
map.name = “illuminance”
map.value = cmd.scaledSensorValue.toInteger()
map.unit = “lux”
break
default:
map.descriptionText = cmd.toString()
}
createEvent(map)
}

def motionEvent(value) {
def map = [name: “motion”]
if (value) {
map.value = “active”
map.descriptionText = “$device.displayName detected motion”
} else {
map.value = “inactive”
map.descriptionText = “$device.displayName motion has stopped”
}
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) {
motionEvent(cmd.sensorValue)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
motionEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def result =
if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
result << motionEvent(0)
result << createEvent(name: “tamper”, value: “clear”, displayed: false)
break
case 3:
result << createEvent(name: “tamper”, value: “detected”, descriptionText: “$device.displayName was tampered”)
break
case 7:
result << motionEvent(1)
break
}
} else {
log.warn “Need to handle this cmd.notificationType: ${cmd.notificationType}”
result << createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
result
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
log.debug “ConfigurationReport: $cmd”
def result =
def value
if (cmd.parameterNumber == 9 && cmd.configurationValue[0] == 0) {
value = “USB Cable”
if (!isConfigured()) {
log.debug(“ConfigurationReport: configuring device”)
result << response(configure())
}
result << createEvent(name: “batteryStatus”, value: value, displayed: false)
result << createEvent(name: “powerSupply”, value: value, displayed: false)
}else if (cmd.parameterNumber == 9 && cmd.configurationValue[0] == 1) {
value = “Battery”
result << createEvent(name: “powerSupply”, value: value, displayed: false)
} else if (cmd.parameterNumber == 101){
result << response(configure())
}
result
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug “General zwaveEvent cmd: ${cmd}”
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}

def configure() {
// This sensor joins as a secure device if you double-click the button to include it
log.debug “${device.displayName} is configuring its settings”
def request =

//1. set association groups for hub
request << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId)

request << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId)

//2. automatic report flags
// param 101 -103 [4 bytes] 128: light sensor, 32 temperature sensor, 1 battery sensor → send command 227 to get all reports
request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 226) //association group 1

request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1) //association group 2

//3. no-motion report x seconds after motion stops (default 20 secs)
request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: timeOptionValueMap[motionDelayTime] ?: 20)

//4. motionSensitivity 3 levels: 64-normal (default), 127-maximum, 0-minimum
request << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1,
scaledConfigurationValue:
motionSensitivity == “normal” ? 64 :
motionSensitivity == “maximum” ? 127 :
motionSensitivity == “minimum” ? 0 : 64)

//5. report every x minutes (threshold reports don’t work on battery power, default 8 mins)
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) //association group 1

request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 66060) //association group 2

//6. report automatically on threshold change
request << zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: 1)

//7. query sensor data
request << zwave.batteryV1.batteryGet()
request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance

setConfigured(“true”)

commands(request) + [“delay 20000”, zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
}

private def getTimeOptionValueMap() { [
“20 seconds” : 20,
“40 seconds” : 40,
“1 minute” : 60,
“2 minutes” : 260,
“3 minutes” : 3
60,
“4 minutes” : 460,
“5 minutes” : 5
60,
“8 minutes” : 860,
“15 minutes” : 15
60,
“30 minutes” : 3060,
“1 hours” : 1
6060,
“6 hours” : 6
6060,
“12 hours” : 12
6060,
“18 hours” : 6
6060,
“24 hours” : 24
60*60,
]}

private setConfigured(configure) {
updateDataValue(“configured”, configure)
}

private isConfigured() {
getDataValue(“configured”) == “true”
}

private command(physicalgraph.zwave.Command cmd) {
if (state.sec) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}

private commands(commands, delay=200) {
log.info “sending commands: ${commands}”
delayBetween(commands.collect{ command(it) }, delay)
}

1 Like

Hi! Thanks for you input!

I tried it but allthough it does something, it still doen’t work. It only connects, sends data once but doesn’t update.
Maybe it’s the jumper settings on the sensor itself…?

Hi Michiel

Did you manage to make any progress?

I also have a couple I would like to configure - I have tried different device types but don’t get anywhere

Regards

  • Andrew

Hi andrew,

I still haven’t gotten it to work either…
Although I haven’t really had time to try anything the past 2-3 weeks…
:frowning:

Hi guys,

I couldn’t make this work with the Device Handlers suggested initially. I also got the SecurityMEssageEncapsulation Catchall log message. I’m assuming this is a new message sent by a newer version of the PST02-b. The solution is to handle it. I copy/pasted handling code from another DeviceHandler google came up with that handled this message.

Add this to your Device Handler:

// Devices that support the Security command class can send messages in an encrypted form;
// they arrive wrapped in a SecurityMessageEncapsulation command and must be unencapsulated
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
        def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x32: 1]) // can specify command class     versions here like in zwave.parse
        if (encapsulatedCommand) {
            return zwaveEvent(encapsulatedCommand)
        }
}

The next issue was that the UI wouldn’t update when temperature/lux data came in. Leaving the Thing ui and opening it up again, made it update, but no updates while the Thing is open. The solution was to kill the app in IOS, and restart. Apparantly this is a known issue with UI caching.

I haven’t found a solution to the motion always showing as on. I see ON messages coming in, but I don’t see an OFF message coming in. I presume this version of the device doesn’t support this? Anyway, probably a workaround could be to somehow have a timer that resets the motion. I don’t need motion for the moment, so I’m not gonna bother.

Cheers

Hello. Has there been any development on this?
I recently bought a PHI_PST02-1B sensor from philio tech and are trying to get lux and temp to be usable. I can see them in details then I click on the sensor in the things tab but the only thing I can use in routines is the motion sensor.

It would be awesome if someone has made a device handler that works for this.

Thanks.