So first off I want to thank mattjfrank and chrisb for their initial work on the Aeon zwave power strip and the ZWN-RSM2
I’ve been using mattjfrank’s device type for my Monoprice relays for months, they mostly worked ok but when I added in voice control with my Alexa things got more frustrating because Smartthings I would ask Alexa to turn lights on and off and often some lights didn’t work. Voice control it seems REALLY needs to work a high percentage of the time since you can’t just sit there and mash a button like you can in the app.
Eventually I narrowed the loss of current state down to the device type not reporting back when the physical switch was pressed. I spent the last few nights nights debugging and came up with a simple solution that works, I also attempted to clean up the code a bit more.
I intend to do a couple more passes on this code as well as some additional testing but for now here is my MonoPrice Dual Relay device type. If you have any issues please feel free to ask here and I will investigate!
To use this code you need to associate your monoprice dual relay with your hub and then:
- Navigate to the Developer Backend of the smart things website here:
- Click on “My Device Types” which is on the top of the page.
- Click the “New Device Type” button on the top right corner of the Device Types page.
- You will now be presented with a page which has fields, ignore them, instead find the tabbed bar at the top and choose “From Code”
- Now Paste in all of my code which is located here in the post.
- Hit create > Save > Publish > For me
- You have now created my device type and it will now be available to assign to your device.
- From the tabbed bar at the top now choose “My Devices”
- Find your device in the list and click on the name which is a hyperlink.
- From the device Page scroll down and select the edit button.
11.Now on the “Edit Device” page find the “Type” drop down list and select the down arrow. Custom devices that you publish for yourself will always appear at the bottom of the list not in alphabetical order like you might expect! - Find my device type it should be named “MonoPrice Dual Relay” select it.
- Hit the “Update” button at the bottom of the page. You should now be in business!
Optional: These devices only show a single tile in the app . To change the state of the second endpoint you have to go to the properties page of the device where there is a tile for both endpoints. This is NOT ideal I followed this post which shows you how to create a couple virtual tiles for each relay I then took all of my relalys and put them in a group called relays. (this takes them out of the main interface , at least in the old app. Maybe this is not needed in the new app) I also validated that my code change the virtual switch tiles as well as the native ones.
/**
- MonoPrice dual relay multi endpoint Zwave switch
- Author Chad Torkkola based of of Matt Frank based on the work of chrisb for AEON Power Strip
- Date Created: 6/26/2014
- Last Modified: 10/22/2015
*/
// for the UI
metadata {
definition (name: “MonoPrice Dual Relay”, namespace: “Monoprice”, author: “Chad Torkkola”) {
capability “Switch”
capability “Polling”
capability “Configuration”
capability “Refresh”
attribute "switch1", "string"
attribute "switch2", "string"
command "on1"
command "off1"
command "on2"
command "off2"
fingerprint deviceId: "0x1001", inClusters:"0x25, 0x27, 0x60, 0x72, 0x86"
}
simulator {
status “on”: “command: 2003, payload: FF”
status “off”: “command: 2003, payload: 00”
// reply messages
reply "2001FF,delay 100,2502": "command: 2503, payload: FF"
reply "200100,delay 100,2502": "command: 2503, payload: 00"
}
tiles {
standardTile("switch1", "device.switch1",canChangeIcon: true) {
state "on", label: "switch1", action: "off1", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: "switch1", action: "on1", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
standardTile("switch2", "device.switch2",canChangeIcon: true) {
state "on", label: "switch2", action: "off2", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: "switch2", action: "on2", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"configure", icon:"st.secondary.configure"
}
main(["switch1", "switch2"])
details(["switch1","switch2","refresh","configure"])
}
}
// 0x25 0x32 0x27 0x70 0x85 0x72 0x86 0x60 0xEF 0x82
// 0x25: switch binary
// 0x32: meter — no meter
// 0x27: switch all
// 0x70: configuration
// 0x85: association
// 0x86: version
// 0x60: multi-channel
// 0xEF: mark
// 0x82: hail
// parse events into attributes
def parse(String description) {
log.debug “Parsing desc => ‘${description}’”
def result = null
def cmd = zwave.parse(description, [0x60:3, 0x25:1, ])
if (cmd) {
result = createEvent(zwaveEvent(cmd))
}
return result
}
//Reports
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
//log.debug “basic”
[name: “switch”, value: cmd.value ? “on” : “off”, type: “physical”]
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd)
{
//log.debug “SwitchBinary”
[name: “switch”, value: cmd.value ? “on” : “off”, type: “digital”]
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCapabilityReport cmd)
{
// log.debug “multichannelv3.MultiChannelCapabilityReport $cmd”
if (cmd.endPoint == 2 )
{
def currstate = device.currentState(“switch2”).getValue()
// log.debug “$currstate”;
if (currstate == “on”)
sendEvent(name: “switch2”, value: “off”, isStateChange: true, display: false)
else if (currstate == “off”)
sendEvent(name: “switch2”, value: “on”, isStateChange: true, display: false)
}
else if (cmd.endPoint == 1 )
{
def currstate = device.currentState(“switch1”).getValue()
// log.debug “$currstate”;
if (currstate == “on”)
sendEvent(name: “switch1”, value: “off”, isStateChange: true, display: false)
else if (currstate == “off”)
sendEvent(name: “switch1”, value: “on”, isStateChange: true, display: false)
}
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
// log.debug “MultiChannelCmdEncap $cmd”
def map = [ name: "switch$cmd.sourceEndPoint" ]
if (cmd.commandClass == 37){
if (cmd.parameter == [0]) {
map.value = "off"
}
if (cmd.parameter == [255]) {
map.value = "on"
}
map
}
/*else if (cmd.commandClass == 50) {
// bitAddress: false, command: 2, commandClass: 50, destinationEndPoint: 1, parameter: [33, 100, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0], res01: false, sourceEndPoint: 1
def hex1 = { n -> String.format("%02X", n) }
def desc = "command: ${hex1(cmd.commandClass)}${hex1(cmd.command)}, payload: " + cmd.parameter.collect{hex1(it)}.join(" ")
// Re-assign source end point 3-6 to 1-4 and 1-2 to 5-6 to sync up with the switch end points.
// Source end point in the message refers to always-on sockets.
} zwaveEvent((cmd.sourceEndPoint > 2) ? (cmd.sourceEndPoint-2) : (cmd.sourceEndPoint+4), zwave.parse(desc, [ 0x60:3, 0x25:1, 0x32:1, 0x70:1 ]))
*/
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren’t interested in
[:]
// log.debug “Capture All $cmd”
}
// handle commands
def refresh() {
for ( i in 1…3 )
cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:i, commandClass:37, command:2).format()
cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:i, commandClass:37, command:2).format()
delayBetween(cmds)
}
def poll() {
delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(),
zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
])
}
def configure() {
// log.debug “Executing ‘configure’”
delayBetween([
zwave.configurationV1.configurationSet(parameterNumber:4, configurationValue: [0]).format() // Report reguarly
])
}
//255 is ALL the way on and 0 is off
def on1() {
delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:1, parameter:[255]).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
// zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format(),
])
}
def off1() {
delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:1, parameter:[0]).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
// zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format(),
])
}
def on2() {
delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:1, parameter:[255]).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format()
//zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
])
}
def off2() {
delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:1, parameter:[0]).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format()
// zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
])
}
I will set up a github for this shortly, next I am going to try to work on the MonoPrice smoke detector !