[OBSOLETE..] Monoprice Dual Relay On/Off Device type 11990

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:

  1. Navigate to the Developer Backend of the smart things website here:
  2. Click on “My Device Types” which is on the top of the page.
  3. Click the “New Device Type” button on the top right corner of the Device Types page.
  4. 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”
  5. Now Paste in all of my code which is located here in the post.
  6. Hit create > Save > Publish > For me
  7. You have now created my device type and it will now be available to assign to your device.
  8. From the tabbed bar at the top now choose “My Devices”
  9. Find your device in the list and click on the name which is a hyperlink.
  10. 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!
  11. Find my device type it should be named “MonoPrice Dual Relay” select it.
  12. 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 !

4 Likes

Thanks. I just tried it out, and it seems to work! The status is reported correctly on the app, even if a physical switch is toggled. Will you plan to update the smartapp virtual buttons too? That app is kind of nice, since it allows each switch to be seen individually. Right now, the status works with your new device type, but doesn’t get reflected in the virtual buttons.

I have virtual buttons set up and they do work. I’m at work for too many more hours today but I’m going to clean this up and up provide links to what I’m using tonight or tomorrow. Glad it works for you.

I updated your posting category and added monoprice’s part number to your title so that it’s easier to find. I will review your code and update my enerwave if it works for it. I just have to get to one of my devices because they are in the fan canopies.

Thanks for your work

Thanks!

The main differences are one added multi channel event handler and in each of the actions for the buttons the bottom line references the opposite end point so I commented it out.

That section is a little confusing to me so I want to look at it again tonight when I get home.

Thanks so much for your work initially, I mean that!

Check my original post and I pointed to the post I used to set up my virtual tiles, this is working 100% in my environment. I did have a weird issues today with two lights and my echo integration but I think it is unrelated to my code because they were still working in the app!

Let me know if you see any weirdness!

Do you have the GitHub code? having some copy/paste issues with your code.

This is my first github its probably a mess… but its here.

github

Can you double check if you are using the same virtual button tile as me? I linked mine in the OP , everything is toggling ok for me so I’m curious whats happening to yours.

Sorry for my delayed response. Your new driver worked well enough for me, since the status in the device driver was always accurate, even when mixed in with the physical switch. So I wanted to enjoy it first, before messing with the virtual button app. The issue was that when I turn on from your device driver, or the app, the status on the app was correct, but if I turn on or off from the physical switch, your device driver status was correct, but the app would not show the new status. I went back to the thread, and decided to try Joel’s app instead. It now works. I don’t see much difference between Joel’s version and Matt’s version, so I don’t know if it’s my operator error or system flakiness.

Thanks for the follow up. Everything’s working great now.

1 Like

what smart app can I use on this device type to turn on/off each relay based on a routine/mode? Thanks

This weekend I installed 4 of the MP 11990 dual relays. Using Chad’s Device Type along with the Virtual Tiles he linked to in “Optional” in the OP, I have retrofitted my Ceiling Fans with Lights and included them in SHM and Routines. Here’s a snapshot of the app:

2 Likes

I’ve found a pretty annoying bug that occurs when using the virtual tiles and have been working on it throughout the week. What I have found is sometimes when you toggle the lights on with the switch they will actually flicker on and off. I have a feeling it has something to do with the virtual tile / binder reacting a multiple events that happen when the physical switch is flipped but in order to fix it I have to know alot more than I do about how the events work. Anyone if anyone else is having issues with flickering I am working on it!

anyone getting the below Java error? I am seeing this within the log files of the relay device. But there is no line 157 in your device.

java.lang.NullPointerException: Cannot invoke method leftShift() on null object @ line 157

Yes, I have many of these errors in my logs

Well, in the device type, I commented out the refresh def content and now it works without the Java errors. oddly, it still updates just fine. Something is broken in that def, but I havent had time to debug.

You will have to delete any virtual button bindings and redo them.

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)
}

Thanks I am in the process of doing a top down re-write or at least audit of all of the code as a learning experience I will look at this closely!

A refresh method that would get the job done and not throw errors could be:

def refresh() {
def cmds =
for ( i in 1…3 ){
cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:i, commandClass:37, command:2).format()
}
delayBetween(cmds)
}

I don’t have this relay, so I can’t tell for certain, but I don’t see how it is showing status updates when the physical switch is toggled. My friend has this switch and I was looking at his logs today. It is very similar to the Philio PAN04 in that when the physical switch is flipped, the relay sends a SwitchBinaryReport event. This event does not specify which physical switch is flipped. My device type for the Philio, when it receives a SwitchBinaryReport, requests for the switch to send it an updated status using the COMMAND_CLASS_MULTI_CHANNEL_V3 command class.

The original SmartApp for the Enerwave would fix this problem by requesting a refresh every minute or so to update the status of both switches. That is why @CDJ is seeing all those null object errors in his logs. The SmartApp is requesting a refresh from your device type about every minute, and then the system is throwing that error.

I had my friend try my Philio device type with his Monoprice dual relay and it works well. Status updates and all. Looking at the log, it looks like the devices act the same except the Philio supports energy reporting.

If anyone wants to try my Philio device type out, below is the link. Also, one advantage of my device type is the SmartApp no longer needs to trigger a refresh of the switch every minute. I’ve included a link for that as well.

Eric, This worked PERFECTLY for me. Thank you! I have the Vision ZL7432US Dual Relays in several places throughout the house and now everything syncs between the manual switch and virtual switches. Thanks again!