MIMOlite Garage Door Sensor with Position Indicator

dth_garage
dth_sensors
dth_misc

(Simon) #1

I have a regular Sears door opener with a button that either opens or closes the door.

Initially I got the solution that @johnconstantelo developed working with a magnetic switch that triggered when the door closed. See Mimolite for garage door and magnetic door contact

This worked find except sometimes the close/open event would get missed. I don’t know if this is linked to current reports of flakey ST service or not but it meant that sometimes the door didn’t report closed or open which made the whole project questionable.

MIMOlite supports a “multi-sensor” feature that reports a variable level, not just a contact sensor, and the bit that is really useful is that it can be programmed to send periodic updates with the value of the sensor, as fast as very 10 seconds. This means that even if the trigger event is lost you’ll still get a message indicating the door position no more than 10 seconds later and you can fix the state of the door in the device handler.
To do this you have to associate the hub with the MMIOlite’s group 2. You then have to add a handler for the SensorMultilevelReport. The code for this looks like this. The first line tells MIMOlite to send the reports to the hub, the second tells it to send a message every 10 seconds, it sends a report ever scaledConfigurationValue * 10 seconds. Add this to the configure() function.

zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format(),
zwave.configurationV1.configurationSet(scaledConfigurationValue: 1, parameterNumber: 9, size: 2).format(),

NOTE: The configurationSet() has a size:2, not size:1 like all the existing handlers use, this doesn’t work, all configure command for MIMOlite must use size:2.

You can then create this handler to test if the door is closed, this is what you’d do if you modified @johnconstantelo device handler.

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv1.SensorMultilevelReport cmd) {
    // the cmd.scaledSensorValue goes to zero when the door is closed, well almost zero
    // so treat anything less than 20 as zero
    sensorValueEvent( (cmd.sensorValue < 20) ? 0 : 0xff )
}

Also in the parse function you need to tell the parser to use 0x31: 1 (multisensor version 1).
Look for a line like this in the parse() function and make sure it has 0x31: 1 in it. If if has 0x31: 3 or 0x31: 2 change it to 0x31: 1.

def cmd = zwave.parse(description, [ ... , 0x31: 1, ... ]

I then decided to change the design to only use the multisensor, it provides much more information about the door position that a contact sensor.
I removed the contact switch and replaced it with with a potentiometer that connects to the rotating bar at the top of the garage door. This means that instead of getting an on/off indication I get the exact position the door is at. Also the MIMOlite can be programmed to send out an alert when the door is closed and open. If the door gets stuck half way up you can actually tell how far open it is.

Another bonus about this is that it now shows opening/closing states on the ST app even when you use the button on the garage wall or the old fashioned garage door remote control.

I used a WXD3-13 2W 10K ohm Multi Turn Poteniometer from amazon ($6 for 2) and hooked it up like it is shown in this web site How-to-install-poteniometer.
The only difference is that you hook up the 2 wires from the potentiometer to the SIG1 input on the MIMOlite. If you’ve wired up the contact switch already you can use the same two wires you connected to it to connect to the potentiometer. (you can’t use both sensors at the same time, so disconnect the magnetic sensor if you connect a potentiometer).

The device handler for the code is below. It is a complete rewrite from the original one.

If you use this you do need to calibrate the door when you first install it. There are 2 configure buttons on the device screen, press the “closed” one when the door is closed and the “open” one when the door is open, this records the position at which your particular door is at when it is open and closed so it can tell when your door is open and closed. (It also shows what position value was recorded).

There is also a display of the raw position of the door that is only there for debugging and geek value.

The way I’ve written the hander it doesn’t matter which way the potentiometer is wired, it figures out if you’ve wired it “backwards” and should work.

/**
 *  MIMOlite as a Garage Door Control with Potentiometer Multi Sensor
 *
 *  Copyright 2016 Simon Capper
 *
 *  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.
 *
 * Inspired by a similar handler written by https://community.smartthings.com/users/johnconstantelo
 */
metadata {
    definition (name: "MIMOlite - Garage Door Control", namespace: "skyjunky", author: "Simon Capper") {
        capability "Polling"
        capability "Refresh"
        capability "Momentary"
        capability "Configuration"
        capability "Garage Door Control"
        attribute "powerSupply", "string"
        attribute "doorPosition", "number"
        attribute "doorPositionClosed", "number"
        attribute "doorPositionOpen", "number"
        command "setOpenPosition"
        command "setClosedPosition"
        fingerprint deviceId:"0x1000", inClusters:"0x72, 0x86, 0x71, 0x30, 0x31, 0x35, 0x70, 0x85, 0x25"
    }

    // UI tile definitions
    tiles(scale:2) {
        multiAttributeTile(name:"door", type: "generic", width: 6, height: 4){
            tileAttribute ("device.door", key: "PRIMARY_CONTROL") {
                attributeState "open", label: "Open", action: "push", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e", nextState:"closing"
                attributeState "opening", label: "Opening", action: "push", icon: "st.doors.garage.garage-opening", backgroundColor: "#ffffff", nextState:"closing"
                attributeState "closed", label: "Closed", action: "push", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", nextState:"opening"
                attributeState "closing", label: "Closing", action: "push", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffffff", nextState:"opening"
                attributeState "unknown", label: "Power Out", icon: "st.alarm.alarm.alarm", backgroundColor: "#bc2323"
            }
            tileAttribute ("powerSupply", key: "SECONDARY_CONTROL") {
                attributeState "good", label: "Power Good"
                attributeState "powerOutOpen", label: "Power Out - Door Open"
                attributeState "powerOutClosed", label: "Power Out - Door Closed"
            }
        }
        valueTile ("doorPositionOpen", "device.doorPositionOpen", width: 5, height: 1) {
            state "doorPositionOpen", label: 'Configured Open Position ${currentValue}'
        }
        standardTile ("setOpenPos", "setOpenPos", decoration: "flat" ) {
            state "setOpenPos", label: '', action: 'setOpenPosition', icon: "st.secondary.configure"
        }
        valueTile ("doorPositionClosed", "device.doorPositionClosed", width: 5, height: 1) {
            state "doorPositionClosed", label: 'Configured Close Position ${currentValue}'
        }
        standardTile ("setClosedPos", "setClosedPos", decoration: "flat") {
            state "setClosedPos", label: '', action: 'setClosedPosition', icon: "st.secondary.configure"
        }
        valueTile ("doorPosition", "device.doorPosition", width: 5, height: 1) {
            state "doorPosition", label: 'Current Door Position ${currentValue}'
        }

        main "door"
        details(["door", "doorPositionOpen", "setOpenPos", 
                 "doorPositionClosed", "setClosedPos", "doorPosition"])
    }
}

def parse(String description) {
    def result = null
    // supported classes
    // 0x20 - BasicSet used to report when the sensor trigger level changes
    // 0x25 - switch binary V1
    // 0x30 - sensor binary V1
    // 0x31 - sensor multilevel V1
    // 0x35 - meter pulse (not tested)
    // 0x70 - configuration V1
    // 0x71 - alarm V1 (for supply voltage monitor, does not seem to respond to AlarmGet)
    // 0x72 - manufacturer specific V1
    // 0x85 - association V1
    // 0x86 - version V1

    def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x86: 1, 0x30: 1, 0x31: 1, 0x72: 1, 0x71: 1])
    if (cmd) {
        result = createEvent(zwaveEvent(cmd))
        if (result) {
            log.debug "Parsed command: ${result?.descriptionText} raw: ${description}"
        } else {
            log.debug "Unhandled command: ${description}"
        }
    } else {
        log.debug "Unparsed command: ${description}"
    }
    return result
}

def getSensitivity() {
    return 0x1
}

def getPotOpen() {
    def rc = device.currentValue("doorPositionOpen")
    if (rc == null) {
        sendEvent(name: "doorPositionOpen", value: 158)
        return 158
    }
    return rc
}

def getPotClosed() {
    def rc = device.currentValue("doorPositionClosed")
    if (rc == null) {
        sendEvent(name: "doorPositionClosed", value: 0)
        return 0
    }
    return rc    
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
    // trigger fires, request the door position so we can see what state it is in
    poll().collect { sendHubCommand(new physicalgraph.device.HubAction(it)) }
    return null
}

def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
    if (cmd.alarmLevel) {
        if (device.currentValue("door") == "closed") {
            sendEvent(name: "powerSupply", value: "powerOutClosed")
        } else {
            sendEvent(name: "powerSupply", value: "powerOutOpen")
        }
        return [name: "door", value: "unknown"]
    }
    return null
}

def convertSensorValueToDoorState( BigDecimal sensorValue ) {
    def upper = (potOpen < potClosed) ? potClosed : potOpen
    def lower = (potOpen > potClosed) ? potClosed : potOpen
    def upperState = (potOpen > potClosed) ? "open" : "closed"
    def lowerState = (potOpen < potClosed) ? "open" : "closed"

    if (sensorValue >= (upper - sensitivity)) {
        return upperState
    } else if (sensorValue <= (lower + sensitivity)) {
        return lowerState
    } else if (device.currentValue('door') == "open") {
        return 'closing'
    } else if (device.currentValue('door') == "closed") {
        return 'opening'
    }
    return device.currentValue('door')
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv1.SensorMultilevelReport cmd) {
    // if we are in a power fail state this is the first message we'll get after the power comes back
    // so update the powerState
    if (device.currentValue('powerSupply') != "good") {     
        sendEvent(name: "powerSupply", value: "good")
    }
    
    def adjustedValue = cmd.scaledSensorValue.intValue() >> 4
    if (adjustedValue != device.currentValue('doorPosition')) {
        def doorState = convertSensorValueToDoorState( adjustedValue )
        sendEvent(name: "doorPosition", value: adjustedValue)
        if (device.currentValue('door') != doorState) {     
            return [name: "door", value: doorState]
        }
    }
    return null
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
    // Handles all Z-Wave commands we aren't interested in
    return null
}

def setOpenPosition() {
    sendEvent(name: "doorPositionOpen", value: device.currentValue('doorPosition'))
    setTriggerLevels().collect { sendHubCommand(new physicalgraph.device.HubAction(it)) }
}

def setClosedPosition() {
    sendEvent(name: "doorPositionClosed", value: device.currentValue('doorPosition'))
    setTriggerLevels().collect { sendHubCommand(new physicalgraph.device.HubAction(it)) }
}

def open() {
    if (device.currentValue("door") == "closed") {
        push()
    }
}

def close() {
    if (device.currentValue("door") == "open") {
        push()
    }
}

def push() {
    def cmds = delayBetween([
        zwave.switchBinaryV1.switchBinarySet(switchValue: 0xff).format(),
    ],500)
    return cmds
}

def poll() {
    delayBetween([
        zwave.sensorMultilevelV1.sensorMultilevelGet().format(),
    ],500)
}

def refresh() {
    delayBetween([
        zwave.sensorMultilevelV1.sensorMultilevelGet().format(),
    ],500)
}

def updated() {
    // called when the device is updated
    configure()
}

def installed() {
    // called when the device is installed
    configure()
}

def setTriggerLevels() {
    def openVal = getPotOpen()
    def closedVal = getPotClosed()
    def slop = getSensitivity()

    // if the potentiometer is installed backwards reverse the parameters
    if (openVal < closedVal) {
        def temp = closedVal
        closedVal = openVal
        openVal = temp
    }

    def lowerValHigh = closedVal + (2 * slop)
    def lowerValLow = closedVal + slop
    def upperValHigh = openVal - slop
    def upperValLow = openVal - (2 * slop)   

    delayBetween([
        // Lower Threshold, High (Default=0xBB)
        zwave.configurationV1.configurationSet(scaledConfigurationValue: lowerValHigh, parameterNumber: 4, size: 2).format(), 
        // Lower Threshold, Low (Default=0xAB)
        zwave.configurationV1.configurationSet(scaledConfigurationValue: lowerValLow, parameterNumber: 5, size: 2).format(), 
        // Upper Threshold, High (Default=0xFF)
        zwave.configurationV1.configurationSet(scaledConfigurationValue: upperValHigh, parameterNumber: 6, size: 2).format(),
        // Upper Threshold, Low (Default = 0xFE)
        zwave.configurationV1.configurationSet(scaledConfigurationValue: upperValLow, parameterNumber: 7, size: 2).format(), 
    ],500)
}

def configure() {
    log.debug "configure"
    def cmds = delayBetween([
       // enable analog alert thresholds
        zwave.configurationV1.configurationSet(scaledConfigurationValue: 0, parameterNumber: 8, size: 2).format(),
        // turn on momentary button press, this presses it for 1 second
        zwave.configurationV1.configurationSet(scaledConfigurationValue: 10, parameterNumber: 11, size: 2).format(),
        // tell device to send multivalue sensor updates every 10 seconds 
        zwave.configurationV1.configurationSet(scaledConfigurationValue: 1, parameterNumber: 9, size: 2).format(),
        // enable alarms to be sent to smartthings hub
        zwave.associationV1.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format(),
        // enable multivalue sensor updates to be sent to smartthings hub
        zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format(),
     ],500)
     cmds += setTriggerLevels()
     return cmds
}

Mimolite for garage door and magnetic door contact
Mimolite input capability?
Z-Wave equivalent of X10 PowerFlash Interface (LV contact input transmitter)?
MIMOlite as a Burg Alarm Control and Monitor with Fire, Burg, Armed, and Disarmed capability
MIMOlite as a Burg Alarm Control and Monitor with Fire, Burg, Armed, and Disarmed capability
#2

Wow @skyjunky, that’s really cool with what you’ve done with a MIMOLite. These devices are capable of so many other uses than just a simple relay, and your use case is a great example.

Thanks for sharing!


(Beckwith) #3

Wow, clever set up.

One concern I have is how long a potentiometer would work in this environment. They tend to burn out over time in my experience.

Regardless, this is a great solution and may provide solutions for other applications.


(Simon) #4

I did look into this as I had the same concern too, this is what I found out

The pot is rated at 2W and up to 160V. In this setup it is only getting 13.5V and with the input resistance of the MIMOlite itself (34 Ohms DC) the power dissipation will be negligible.

operation cycles for this device vary by manufacturer, but somewhere between 10,000 and 1,000,000 is what I’ve found. If you open/close your door 5 times a day it will last between 2.7 and 270 years. I hope the one I bought is somewhere in the middle :slight_smile:


(Eric) #5

Fun application, thanks for sharing.


(Damon Distefano) #6

Hi Simon, I would like to say it is really smart to come out with this idea, to be on the safe side regarding the true position of the garage door. I am in process to use the poteniometer instead of the magnetic contact, I have recently follow Johnconstantelo code, and get my mimolate configure based on his code. I purchase poteniometer from Amazon and connect the 2 wires to the SIG. copy and paste your code in my device handler. configure the SmartApp. But when I decided to test it it dose not works, I can not even get the garage door to open/close! My question, is there anything else I have to do in order to get it works? Thank you.


(Damon Distefano) #7

Got I fix. Had to reset the Mimolite and reconfigure it with your code. I was able to open/ close garage door, but without current status of the door! Then I realize that my wires were connected to the wrong pins! I switched them out and now everything works perfectly. Thank you for your code Simon.


(Damon Distefano) #8

They new issue I’m facing is, I can’t get Amazon echo to discover it, it used to work with Johnconstantelo code. are having any issue with using it with Amazon echo?
Thank you.


(Simon) #9

Thanks for the pictures, that really helps explain how to wire up the potentiometer I should have included them in the original post.
What you have looks exactly like the wiring I have.


(Damon Distefano) #10

You’re welcome. Is yours discoverable by Amazon echo? I can’t get mine to ? Can you please help me so I can control it using Amazon Echo?
Thank you.


(Simon) #11

I don’t use an Amazon Echo.
The device handler does register itself as a garage door opener, I’d look for advice on how the echo works with garage door openers in general.

If you have any log or info from the echo or the device handler I can look at them to see if anything is obviously wrong if you like.


#12

@skyjunky and @Damon_Distefano,

I can’t remember off hand which thread discussed it, but something changes with Alexa not too long ago. I also mentioned it in another thread.

I use to be able to say “Alexa, open garage door” or “Alexa, close garage door”, with garage door being the name of my device obviously. That no longer works,and it’s not because of anything ST did or my DH, it’s all on Amazon’s side of things.

I now have to say “Alexa, turn off garage door” or “Alexa, turn on garage door” for it to work.

My DH doesn’t do anything special for Alexa. It uses the “switch” capability that allows someone to select the device in the Amazon Echo SmartApp, which then can be discovered when saying “Alexa, discover new devices”. It’s about as simple as it gets.


(Damon Distefano) #13

Well, the thing is, with Simon DH code is that Amazon echo not even able to locate it! I tried to reuse johnconstantelo DH code, it’s work fine, Amazon echo can recognize it and it work with the turn on/off command. Amazon echo also able to descover it as the zwave switch. But when I use Mimolite garage door sensor with position, Simon code. Amazon can not discover it no more! Can you guys help me out to figure out what’s going on?
Thanks for you guys help.


#14

I know why! Add this line of code to Simon’s DH code you are using:

capability “Switch”

I would also add this one too:

capability “Actuator”

After doing that, go back through adding this to Alexa.


(Damon Distefano) #15

Thank you johnconstantelo. I was suspicious about the switch phrase, after comparing your DH code with Simon code, I figure out it was missing something, but I am still now with the ST. Alexa was able to discover the Mimolite as switch and now executing the turn on/off command right after adding the “Switch and Actuator” phrase to the DH code, however; it’s still not able to open/close the actual garage door?

808cbeb1-ef04-4433-a6d5-fbd2dd4a00f9 11:54:23 PM: debug Unhandled command: zw device: 08, command: 3105, payload: 02 0A 00 01
d80d87d3-c490-45d4-acb7-ea03a6479405 11:54:17 PM: debug Turn on Garage Door

any ideas?
Appreciate your help.


#16

Yup! The code is missing these lines as well:

def on() {
	open()
}

def off() {
	close()
}

Add those lines right above the line “def open()” in the code you are using. This should finally do it for you.


(Damon Distefano) #17

You’re the Man @johnconstantelo. That lil command fix it. Thank you so much for taking the time to help me.
Is there any other way to rewrite the code so Amazon echo recognize it as a regular door opener instead of switch? Can we import the code from the Linear/GoControl GD00Z-4 Garage door opener?


#18

All the capabilities are already in the code for it to be recognized as a door opener, except maybe:

capability “Door Control”

Adding that won’t help Alexa though. Amazon made some change on their end that took away the functionality of the words open and close. It use to work a while back, and now it doesn’t. I don’t use the GD00Z-4, but I suspect it has the same issue. This thread discussed some of the recent changes:


(Simon) #19

Neat debugging of this issue.

What you’ve done it basically make the garage door look like a switch instead of a garage door and now Alexa can
control it.

I guess the Alexa/SmartThing integration isn’t very sophisticated yet, reading about it you can only control switches, dimmers and thermostats.


(Damon Distefano) #20

Thanks for help @johnconstantelo @skyjunky. Appreciate all the time and efforts.