Chamberlain/Liftmaster MyQ Operation Plugin

Jamrs, thanks for your help–that looks doable!

I’m not sure I’m capable of creating a plugin BUT… I have been working a bit with ZeroBrane as an IDE (pretty cool) and using JSON and SSL.HTTPS and I can now in Vera:

  1. Authenticate to myQ and retrieve my SecurityToken
  2. Grab the devices collection and iterate over their attributes, getting door states along with names and IDs
  3. PUT a JSON request that either Opens or Closes the door

The code is ugly, I’m bad at this… I can post it once I’ve cleaned it up but it does work

Great progress. I wish I had the skills to help. I really hope one day to get my doors linked into Vera and not have to use a separate app. Also I could free up a couple of Z-wave sensors that are currently monitoring the doors.

I figure I might as well post my code (Hold your nose, this is my first time with LUUP, LUA, etc)
As I mentioned, I’m using ZeroBrane’s IDE and am submitting this code to my Vera … I’m not sure if this will run if you submit directly from within Vera, you might have to change the print statements to luup.log ??

I’m using 2 “libraries” that were already installed from other plugins:

json and ssl.https

What I’ve written might offend you, or quite possibly, sicken you but it is my first try at this so be forewarned with that knowledge.

I don’t really have any error handling in the code at all. You basically can make a couple of changes to the code:

  1. Change username to be your myQ username
  2. Change password to be your myQ password
  3. Change doorAction to be 0 for Open OR 1 for Close

Then run it… It’ll authenticate into myQ, get a security token
next it’ll loop over your devices and print out information about your garage door openers (basically name and device ID)
next it will open or close them ALL depending upon what doorAction was set to.

So, all that aside – should I attempt to continue with this? Please offer any comments on where I’ve gone horribly wrong in the code.

Ok…Code follows [hold your nose]

--Change these to match the authentication used to access your MyQ account
local username=""
local password = ""

--Action: 1=Open, 0=Close
local doorAction = 0

--Libraries
local json = require("json")
local https = require("ssl.https")

--Table to hold the device id and device names of the garage doors found
local garageDoors = {}
local responseText = ""

--Actions for doors
local doorActions = {[0] = "close",
                     [1] = "open"}
                    
--Statuses for doors
local doorStatuses = {["1"] = "open",
                      ["2"] = "closed",
                      ["4"] = "opening",
                      ["5"] = "closing"}
                      
--These should not change but who knows
local appId = "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB%2fi"
local baseURL = "https://myqexternal.myqdevice.com/"
local validationPath = "Membership/ValidateUserWithCulture"
local UserDeviceDetails = "api/UserDeviceDetails"
local SecurityToken

--Access URLs
local auth_string = validationPath .. "?appId=" .. appId	 .. "&username=" .. username .. "&password=" .. password .. "&culture=en"

--And away we go.. 
--httpStatusCode(Number) and content (String) are returned
local authStatusCode, authContent = luup.inet.wget(baseURL .. auth_string)

--Check our return code, 0 is a success
if( authStatusCode == 0 ) then
  authContent = json.decode(authContent)
   --Did we auth successfully? ReturnCode is a char..
   if( authContent.ReturnCode == "0" ) then
     --This has to get persisted at some point
     --When does it expire?
     SecurityToken = authContent.SecurityToken
    else
      print("Authentication Error")     
   end   
else
  print("Unsuccessful at connecting with authorization URL!")
end

--Time to inspect what devices there are..
local deviceURL = baseURL .. UserDeviceDetails ..  "?appId=" .. appId .. "&securityToken=" .. SecurityToken
local deviceStatusCode, deviceContent = luup.inet.wget(deviceURL)

--Decode this sucker
deviceContent = json.decode(deviceContent)

--A 0 appears to indicate we have had a success
if(deviceContent.ReturnCode == "0" ) then
  
  --Time to loop over our device collection
	for i,d in ipairs (deviceContent.Devices) do	
    
    local DeviceName = d.DeviceName
    local DeviceId = d.DeviceId
    
    --TypeId of 49 appears to be the gateway device, only interested in the openers for now
    if( d.TypeId == 47 ) then
      
      --Add our garage door to the table
      garageDoors[DeviceId] = DeviceName      
      
      --Each device has an attributes collection, over it we go
      for j, attr in ipairs ( d.Attributes) do
        if( attr.Name=="desc") then
          responseText = responseText .. "Found garage door named '" .. attr.Value
        elseif( attr.Name == "doorstate" ) then
          local doorstateValue = attr.Value
          if( doorStatuses[doorstateValue] ~= nill) then          
            responseText = responseText .. " and it is " .. doorStatuses[doorstateValue]
          else
            responseText = responseText .. " and it is in an unknown state!" 
          end
        end
      end
    end
  end
end


print(responseText)

--Over our garage door openers we go...
for gDoorDeviceId, gDoor in pairs(garageDoors) do
  
  --Our JSON to be delivered...
  jsonPut = {
              AttributeName = "desireddoorstate",
              DeviceId = gDoorDeviceId,
              ApplicationId = appId,
              AttributeValue = doorAction,
              SecurityToken = SecurityToken
            }
  --JSON encode it for delivery
  json_data = json.encode(jsonPut)
  local response_body = {}
  
  --And now we switch from wget to https.request
  local response, status, header  = https.request{
    method = "PUT",
    url = "https://myqexternal.myqdevice.com/Device/setDeviceAttribute",
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = string.len(json_data)
    },
    source = ltn12.source.string(json_data),
    sink = ltn12.sink.table(response_body)
  }
  if( response == 1) then
    local output = json.decode( response_body[1] )
    if ( output.ReturnCode == "0" ) then
      print("Successfully changed status of door " .. gDoor .. " to " .. doorActions[doorAction])
    end
  end 
end

Nothing horribly wrong, esp since it’s early on…

As you?re building/testing this, it might be easier to do it first via native Lua, and then do the integration work with Vera.

To do this, you can put your code into a Lua module (see Sonos codebase on http://code.mios.com for an example) and then require() it into whatever you want to load it into, much as you?re doing with the json library.

You?d end up needing public methods exposed from this module for things like:
init
methods to trigger Opening/Closing
methods to trigger the Polling of the Service for Status information

You?ll still be able to put luup calls into this code, eventually, but it?ll help to you build/iterate the code. Of course, if you?re already working with the ZeroBrane IDE, this is probably easier anyhow.

This will make it easier to try out stuff without having to call the overall sequence again.

A few generic comments, take them as you will:
a) Use Uppercase variable names for constants.
While not required, it?ll make reading the code easier for those used to that convention :wink:
This is for stuff like baseURL, UserDeviceDetails, (etc)

b) Apply an appropriate encoding to the username/password, securityToken (etc) parameters in URLs that are built.
It?s likely that folks will have special characters in their Passwords, and perhaps in their Usernames as well. Best to run the appropriate encoding over the top of these values as you?re glueing the string together. even if only to avoid problems down the line. It would also apply the encoding on anything you get back from the calls, such as securityToken, just to be sure.

c) In some cases you?re using luup.inet.wget, and others you?re using https.request.
Might as well use https.request in both places for consistency. It?ll also help you run this [module] freestanding (without Vera) if you want to iterate development faster.

Set the timeout on these, since Vera will puke if the code takes too long to return, and the biggest source of that is long-running HTTP Calls (typically in failure situations)

d) In the failed HTTP-call case, make the code bail out.
Right now it?ll carry on, but the rest of the code won?t work correctly because the content hasn?t been returned. In Lua, it?s very common for functions to return false as their first return-value to indicate failure.

ie.

if (authStatusCode == 0) then
  authContent = json.decode(authContent)
   --Did we auth successfully? ReturnCode is a char..
   if (authContent.ReturnCode == "0") then
     SecurityToken = authContent.SecurityToken
   else
     return false, "Authentication Error"
   end   
else
  return false, "Unsuccessful at connecting with authorization URL!"
end

There are other options for doing this a well, but this would get you going for now.

e) There are cases where the code should be hardened
No point going over them all now but, for example, it?s possible for a HTTP-based service to error-out and return text/plain or text/html errors. In these cases, the result of the json parser might be nil, or something that you?re not expecting.

f) Define 47 as a const with a memorably name.
It?ll save you writing the code-comments later 8)

g) Define a set of local functions for debug, error and general logging
I found this extremely handy while debugging stuff. You can see examples in code like the DSC Plugin on code.mios.com. These fns all funnel back to the same logging call (typically luup.log, when inside Vera, or print, when outside of Vera)

You can hardcode it against one for now (luup.log if you?re only running inside of Vera) and fix it up later on as needed.

BTW: If you ever want to know if you?re running inside of Vera, you can do something akin to the following at the top of your module:

if (luup == nil) then
  ... -- Vera is not present
end

It?s still a kludge, but it?ll give you a general idea. A more general version is to have an init() method that takes a context [table][tr][td] parameter

[/td][/tr][/table][code]
module(“chamberlain”, package.seeall)


local log, debug, error

function init(ctx)
log = ctx.log
debug = ctx.debug
error = ctx.error
end

function stuff(…)
debug(“hello”)
end
[/code]

and in the calling code, something akin to:

local debug, log, error = function (line) print("debug: " .. tostring(line or '<empty>')) end,
                          function (line) print("log: " .. tostring(line or '<empty>')) end,
                          function (line) print("error: " .. tostring(line or '<empty>')) end

chamberlain.init({debug = debug, log = log, error = error})

This can be expanded to handle ?proxy? methods for all of luup.x, so that your code can be made to work in other environments (to some extent). This can all be compressed, but I?ve left it multi-line to make it more readable.

x) Each plugin in apps.mios.com has it?s ?own? json lib, so rename it now.
apps.mios.com requires that all filenames have no overlaps across all plugins in their catalog. This is a PITA, but it?s the reality today so folks typically rename any overlapping filenames. You?ll see this most commonly for shared libraries (like JSON handling) where prefixes are applied to make it unique-per-plugin. The HTTPS lib is built-in, so no need to do that there.

Anyhow, enough babble for now, hopefully this is helpful.

I have ordered the LiftMaster IP Gateway, so I can try out the fruits of your labor :wink:

guessed - WOW, thanks for the very thoughtful response. I need time to digest it but I’m going forward with the plugin. Thanks for inspiring me, hopefully I can create something useful

thank you!

Alright, some more work done. This thing is growing into a bear, hopefully it’s a bit cleaner and makes more sense. I’m really clueless at this and now have over 300 lines of code ???

Let the babbling commence:

I have now created 4 separate functions:

retrieveSecurityToken: Has two returns- authResult and authText
authResult is true or false, if true authText has the SecurityToken if false, it has the reason for a failure in retrieving the security token
Is the way I’m returning the result(s) bad form? So there would be a timer calling this and keeping this in “state” in Vera eventually

inspectDevices: Has two returns ( though should be 3 ) one is a table of tables that builds up info about the devices [ID, Names, Description, door status] – I imagine this general code could create all the original devices [left garage door opener with associated device id and device name] – on reloads does a plug check all of these again so that you can automatically add new openers if they are found?

changeGarageDoorState: opens or closes a given garage door. The action buttons on a plugin, I’d presume

getGarageDoorStatus: shows the current state of a given garage door [open, opening, closing, closed]. Showing the current state on the plugin

They are all working

I’ve implemented some of your suggestions (others I don’t know how to or haven’t gotten to):

I don’t have a clue as to how to set the timeout on the ssl.https requests, any pointers?

a) I’ve tried to use uppercase for constants. I’m sure I haven’t gotten them all yet

b) I’m now encoding the username and password, lifted a function I found [credit is in the code below]

c) I’ve standardized to using https.request [as an aside, i wonder why this isn’t included in ZeroBrane, evidently it was in a previous version. I was able to find it so all is good but took a bit of searching]

d) I’ve done some rudimentary work on trapping for failed calls but am not really doing anything with it

e) Not quite there, haven’t inspected any returns for detailed info, not sure if what was done in d) is enough?

f) defined :slight_smile:

g) Haven’t wrapped my head around that yet

x) Have not done it, I think it’s the netatmo JSON, so I’ll just call it json_myq or something like that?

Ok… more ugly code:

--[[
The beginning of a plugin to connect to the Chamberlain Liftmaster MyQ API
Unofficial documentation of the API is found here:
http://docs.unofficialliftmastermyq.apiary.io/

There is also a Ruby gem implementation at GitHub:
https://github.com/pfeffed/liftmaster_myq

]]


--Change these to match the authentication used to access your MyQ account
local username=""
local password = ""

--Function found: http://lua-users.org/wiki/StringRecipes
--Used to encode username / password for submission
function url_encode(str)
  if (str) then
    str = string.gsub (str, "\n", "\r\n")
    str = string.gsub (str, "([^%w %-%_%.%~])",
        function (c) return string.format ("%%%02X", string.byte(c)) end)
    str = string.gsub (str, " ", "+")
  end
  return str	
end

--Libraries
local json = require("json")
local https = require("ssl.https")

--These should not change but who knows, follow UPPERCASE convention for names
local APPID = "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB%2fi"
local BASEURL = "https://myqexternal.myqdevice.com/"
local VALIDATIONPATH = "Membership/ValidateUserWithCulture"
local USERDEVICEDETAILS = "api/UserDeviceDetails"
--CONSTANTS for TypeIds in the Devices list
local GARAGEDOOROPENER = 47
local GATEWAYDEVICE = 49
--Access URLs
local auth_string = VALIDATIONPATH .. "?appId=" .. APPID	 .. "&username=" .. username .. "&password=" .. password .. "&culture=en"
                    
--Statuses for doors
local doorStatuses = {["1"] = "open",
                      ["2"] = "closed",
                      ["4"] = "opening",
                      ["5"] = "closing"}
                                       
local SecurityToken

--[[
Connects to the LiftMaster/Chamberlain MyQ API
Returns result and resultText
]]
local function retrieveSecurityToken(authURL, username, password)
  
  local result     --Did we successfully connect and get the SecurityToken, is true or false
  local resultText --If false, the error, if true, the SecurityToken
  
  --Table to hold our response from the call
  auth_response = { }
  
  local response, status, header  = https.request
  {
    url = authURL,
    method = "GET",
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = 0
    },
    sink = ltn12.sink.table(auth_response)
  }
  
  --Check out the response
  if( response == 1 ) then
    --Decode our JSON, we have a response
    authResponseData = json.decode( auth_response[1] )
    
    --Check our return code
    if( authResponseData.ReturnCode == "0" ) then
      result = true
      resultText = authResponseData.SecurityToken
     else
       result = false
       resultText = "Authentication Error!"
     end
  else
    result = false
    resultText = "Unsuccessful at connecting with the authorization URL!"
  end
  return result, resultText  
end

--[[
Inspect all devices associated with the MyQ
]]
local function inspectDevices(deviceURL, SecurityToken)
  
  local connectionResult      --True if successful, false if not
  local connectionText        --Holds issue with connection
  local openerInfo = {}       --Table to hold info about openers
  local device_response = { } --Table to hold our response from the call
  
  --Fire up our connection 
  local response, status, header = https.request
  {
    url = deviceURL,
    method = "GET",
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = 0
    },
    sink = ltn12.sink.table(device_response)
  }

  --Check out our response
  if( response==1 ) then
    --Decode our JSON: Am unclear as to why device_response[1] threw an error
    --local deviceContent = json.decode( device_response[1] )
    local deviceContent = json.decode(table.concat(device_response))
    
    --A 0 appears to indicate we have had a success
    if(deviceContent.ReturnCode == "0" ) then
      connectionResult = true
      local numOpeners = 0
    
      --Time to loop over our device collection
	    for i,d in ipairs (deviceContent.Devices) do	
    
        local DeviceName = d.DeviceName
        local DeviceId = d.DeviceId
        local ParentName
   
        --TypeId of 49 appears to be the gateway device
        --Useful here might be the desc which is the name in MyQ (e.g. Home)
        --Perhaps that should be the name of the parent device?
        if( d.TypeId == GATEWAYDEVICE ) then
          for k, attr in ipairs( d.Attributes ) do
            if( attr.Name == "desc" ) then
              ParentName = attr.Value
            end
          end
        end
      
        --TypeId of 47 appears to be the individual garage door openers
        if( d.TypeId == GARAGEDOOROPENER ) then
        
          --Stop the presses, we found an opener
          numOpeners = numOpeners +1
          local doorState
          
          --Each device has an attributes collection, over it we go
          for j, attr in ipairs ( d.Attributes) do
            if( attr.Name == "desc") then
              openerName = attr.Value
            elseif( attr.Name == "doorstate" ) then
              local doorstateValue = attr.Value
              if( doorStatuses[doorstateValue] ~= nill) then
                doorState = doorStatuses[doorstateValue]
              else
                doorState = "ERROR: Unknown State! " .. doorstateValue
              end
            end
          end
          
          --Keep track of all the openers along with their state
          table.insert(openerInfo, numOpeners, {
                                                DeviceId = DeviceId,
                                                DeviceName = DeviceName,
                                                DoorState = doorState,
                                                OpenerName = openerName
                                               })
        end
      end
    else
      connectionResult = false
      connectionText = "Failed call to the MyQ API, perhaps refresh of token needed?"
    end
  else
    connectionResult = false
    connectionText = "Unsuccessful at connecting with device URL!"
  end
  return connectionResult, openerInfo
end

--[[
  Check on the status of a given garage door opener
]]
local function getGarageDoorStatus(deviceURL, SecurityToken, DeviceId)
  local connectionResult      --True if successful, false if not
  local connectionText        --Holds issue with connection
  local device_response = { } --Table to hold our response from the call
  
  --Fire up our connection 
  local response, status, header = https.request
  {
    url = deviceURL,
    method = "GET",
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = 0
    },
    sink = ltn12.sink.table(device_response)
  }

  --Check out our response
  if( response==1 ) then
    --Decode our JSON: Am unclear as to why device_response[1] threw an error
    --local deviceContent = json.decode( device_response[1] )
    local deviceContent = json.decode(table.concat(device_response))
    
    --A 0 appears to indicate we have had a success
    if(deviceContent.ReturnCode == "0" ) then
      connectionResult = true    
      --Time to loop over our device collection
	    for i,d in ipairs (deviceContent.Devices) do	
   
        -- Only interested in our specified garage door opener
        if( d.TypeId == GARAGEDOOROPENER and d.DeviceId == DeviceId ) then
          local doorState
          for j, attr in ipairs ( d.Attributes ) do
            if( attr.Name == "doorstate" ) then
              local doorstateValue = attr.Value
              if( doorStatuses[doorstateValue] ~= nill) then
                connectionText = doorStatuses[doorstateValue]
              else
                connectionText = "ERROR: Unknown State! " .. doorstateValue
              end
            end
          end
        end
      end
    else
      connectionResult = false
      connectionText = "Failed call to the MyQ API, perhaps refresh of token needed?"
    end
  else
    connectionResult = false
    connectionText = "Unsuccessful at connecting with device URL!"
  end
  return connectionResult, connectionText
end

--[[
  Change the state of a garage door. Basically a doorstate of 1 is open and a doorstate of 0 is close
  DeviceId is found in the output of inspectDevices
]]
local function changeGarageDoorState(DoorDeviceId, AppId, DoorAction, SecurityToken)

  local result     --Result of the action, true or false
  local resultText --Summary of the result
  local doorActions = {[0] = "close",
                       [1] = "open"}

  --Our JSON to be delivered...
  jsonPut = {
              AttributeName = "desireddoorstate",
              DeviceId = DoorDeviceId,
              ApplicationId = AppId,
              AttributeValue = DoorAction,
              SecurityToken = SecurityToken
            }
            
  --JSON encode it for delivery
  json_data = json.encode(jsonPut)
  
  local response_body = {}
  
  --Fire up our request, noting that we are using the PUT method and setting our content length in the header
  local response, status, header  = https.request{
    method = "PUT",
    url = "https://myqexternal.myqdevice.com/Device/setDeviceAttribute",
    headers = {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = string.len(json_data)
    },
    source = ltn12.source.string(json_data),
    sink = ltn12.sink.table(response_body)
  }
  if( response == 1) then
    local output = json.decode( response_body[1] )
    if ( output.ReturnCode == "0" ) then
      result = true
      resultText = "Successfully changed status to " .. doorActions[DoorAction]
    else
      result = false
      resultText = "Authentication error. Perhaps token expired?"
    end
  else
    result = false
    resultText = "Unsuccessful at communicating with the setDeviceAttribute service"
  end 
  
  return result, resultText
end



------------------------------------------
--
-- Time to use the functions...
--
------------------------------------------

--Get our security token, making sure we encode our username and password
local authResult, authText = retrieveSecurityToken(BASEURL .. auth_string, url_encode(username), url_encode(password))

--Is everything ok here?
if(authResult == true ) then
  print("Success, security token is: " .. authText)
  SecurityToken = authText
else
  print("ERROR: Message is " .. authText)
end

--Swing away, let's see what we have for devices..
local connectionResult, openerInfo  = inspectDevices(BASEURL .. USERDEVICEDETAILS ..  "?appId=" .. APPID .. "&securityToken=" .. SecurityToken, SecurityToken)

print("I see that you have " .. #openerInfo .. " garage door openers:")  
for i=1, #openerInfo do
  print( openerInfo[i].OpenerName .. " is currently " .. openerInfo[i].DoorState)
end

--Action: 1=Open, 0=Close
--Let's close a door from above..
result, resultText = changeGarageDoorState(openerInfo[2].DeviceId, APPID, 0, SecurityToken)
print(result)
print(resultText)

socket.sleep(3)

--Check on the status..
local gdStatus, gdStatusText = getGarageDoorStatus(BASEURL .. USERDEVICEDETAILS ..  "?appId=" .. APPID .. "&securityToken=" .. SecurityToken, SecurityToken, openerInfo[2].DeviceId)
print(gdStatusText)

I created another thread about my attempt at making a plugin for this device: http://forum.micasaverde.com/index.php/topic,24715.0.html

The bad news is that I’m a crappy programmer
The good news is that I have a proof of concept working.

The plugin creates a parent device that simply needs your username and password for the MyQ service
After a restart, it inspects all the devices connected to your account and creates children (door locks) for each garage door opener found. These door lock devices have their status updated every 90 seconds to reflect if they are opened or closed and the buttons allow for the doors to be opened or closed

There is a lot more work that has to go into this but am interested in people taking a look and telling me what they think and if I should continue along this path. It’s already taken up a pretty good chunk of time

A few notes:
While the MyQ device exposes gate openers and lights, I’m not looking for either of these as I don’t have any
Also, the MyQ device exposes multiple “Places” as I have only one “Place” - I don’t treat this special at all

Anyway… this all hinges on calls that were reverse-engineered (by others) and could stop working at any time

but there’s at least some success in a (very rough) plugin that can control the openers
I look forward to hearing any comments/feedback

[quote=“BOFH, post:33, topic:170458”]Since Chamberlain also seems to make the Craftsman units, that explains the issues I have trying to integrate that system.

My solution at this time is this $35 [url=http://www.staples.com/Ecolink-Wireless-Garage-Door-Tilt-Sensor-White/product_278640?externalize=certona]http://www.staples.com/Ecolink-Wireless-Garage-Door-Tilt-Sensor-White/product_278640?externalize=certona[/url] tilt sensor. It will tell Vera if the door is open or not and she will email me if it is open within a certain time frame. I can then use the Craftsman app or website to close the door remotely… (That one is UL certified I am sure as the wall panel scream loudly for about 10 seconds before closing the door.)

I would love to be able to automate it, but worry about liability with a DIY solution that does not adhere to the UL requirements.[/quote]

MY OLD SETUP: I used to be able to open/close my old Craftsman GDO with my Vera2 using RTS’s Garage Door Plugin, SM-103 sensor, and ZFM-80
MY NEW SETUP: My old Craftsman GDO just gave up after 23 years. I now have a Chamberlain, Ecolink sensor, and MyQ Internet Gateway. I am not sure if I understand it correctly that from what I have been reading in this thread, Chamberlain GDO cannot be presently integrated with Vera. I would appreciate if someone can confirm this so that I can remove my ZFM-80 from the garage and use it somewhere else. thanks in advance.

[quote=“waltzer11, post:69, topic:170458”][quote=“BOFH, post:33, topic:170458”]Since Chamberlain also seems to make the Craftsman units, that explains the issues I have trying to integrate that system.

My solution at this time is this $35 [url=http://www.staples.com/Ecolink-Wireless-Garage-Door-Tilt-Sensor-White/product_278640?externalize=certona]http://www.staples.com/Ecolink-Wireless-Garage-Door-Tilt-Sensor-White/product_278640?externalize=certona[/url] tilt sensor. It will tell Vera if the door is open or not and she will email me if it is open within a certain time frame. I can then use the Craftsman app or website to close the door remotely… (That one is UL certified I am sure as the wall panel scream loudly for about 10 seconds before closing the door.)

I would love to be able to automate it, but worry about liability with a DIY solution that does not adhere to the UL requirements.[/quote]
What model opener and wall button do you have?

MY OLD SETUP: I used to be able to open/close my old Craftsman GDO with my Vera2 using RTS’s Garage Door Plugin, SM-103 sensor, and ZFM-80
MY NEW SETUP: My old Craftsman GDO just gave up after 23 years. I now have a Chamberlain, Ecolink sensor, and MyQ Internet Gateway. I am not sure if I understand it correctly that from what I have been reading in this thread, Chamberlain GDO cannot be presently integrated with Vera. I would appreciate if someone can confirm this so that I can remove my ZFM-80 from the garage and use it somewhere else. thanks in advance.[/quote]

hi Jamr, my GDO model is WD832KEV. I dont know the model of the wall button-it came with the GDO. i ordered it from home depot. here is the link. http://www.homedepot.com/p/Chamberlain-Whisper-Drive-1-2-HP-Belt-Drive-Garage-Door-Opener-with-MyQ-Technology-WD832KEV/203790226. then i bought the MyQ gateway internet from amazon. thanks for your prompt response.

You should be able to get this to work. You will have to take the normally open output of the ZFM-80 to the wall button controlling your GDO. You will have to crack it open and attach the wires to the wires inside the wall button that close when you press the button. If properly installed, everything including your MyQ system should work properly.

If you have any other questions concerning this, please ask.

[quote=“macrho, post:68, topic:170458”]I created another thread about my attempt at making a plugin for this device: http://forum.micasaverde.com/index.php/topic,24715.0.html

The bad news is that I’m a crappy programmer
The good news is that I have a proof of concept working.

The plugin creates a parent device that simply needs your username and password for the MyQ service
After a restart, it inspects all the devices connected to your account and creates children (door locks) for each garage door opener found. These door lock devices have their status updated every 90 seconds to reflect if they are opened or closed and the buttons allow for the doors to be opened or closed

There is a lot more work that has to go into this but am interested in people taking a look and telling me what they think and if I should continue along this path. It’s already taken up a pretty good chunk of time

A few notes:
While the MyQ device exposes gate openers and lights, I’m not looking for either of these as I don’t have any
Also, the MyQ device exposes multiple “Places” as I have only one “Place” - I don’t treat this special at all

Anyway… this all hinges on calls that were reverse-engineered (by others) and could stop working at any time

but there’s at least some success in a (very rough) plugin that can control the openers
I look forward to hearing any comments/feedback[/quote]

I picked up a VeraLite to use in our new home a couple weeks ago and have been playing with some very basic control getting a feel for how the unit works, one item on my wish list once we move is garage door monitoring and control, the MyQ setup + this plugin would be perfect so I for one am excited for work on the plugin to continue, being able to view status (and alert on it if desired based on set criteria in Vera) and open/close remotely would be fantastic. Huge Kudos to all the work you’ve done already!

You should be able to get this to work. You will have to take the normally open output of the ZFM-80 to the wall button controlling your GDO. You will have to crack it open and attach the wires to the wires inside the wall button that close when you press the button. If properly installed, everything including your MyQ system should work properly.

If you have any other questions concerning this, please ask.[/quote]

(1) inside the wall button not the back right? does this involve soldering?
(2) the open output of the ZFM-80, is it the 2 middle terminals “E” or the 2 top terminals “D”.
therefore, no wires go directly from ZFM-80 to the GDO?
thanks for your patience.

You should be able to get this to work. You will have to take the normally open output of the ZFM-80 to the wall button controlling your GDO. You will have to crack it open and attach the wires to the wires inside the wall button that close when you press the button. If properly installed, everything including your MyQ system should work properly.

If you have any other questions concerning this, please ask.[/quote]

(1) inside the wall button not the back right? does this involve soldering?
(2) the open output of the ZFM-80, is it the 2 middle terminals “E” or the 2 top terminals “D”.
therefore, no wires go directly from ZFM-80 to the GDO?
thanks for your patience.[/quote]

Yes, inside the wall button.
I do not know as I do not have a wall button to test this. From what I have learned from other people that have done this, yes you will have to solder the wires onto the contacts.
I would love to get some photos or better yet, a video of this installation and modification so I can create a “How to” on how to do this with our RM10.
Yes, no wires go from the ZFM-80 to the GDO directly.

Please let me know if you are able to do this.

I just wanted to post a public “thank you” to Jamr–I’m pretty new to this, so getting my gate operator working took some doing, but Jamr was a huge help walking me through the install and helping me troubleshoot when I got into trouble. I’m using the RM10 he makes, hooked into the gate controller–works perfectly for this application.

No problem. Glad you got it working. ;D

so,… any idea when the plugin will be released into the micasaverde plugin store? :smiley: :smiley:

Not sure if it’s going into the App Store, but I just downloaded the latest version machro posted on the other thread–it’s been working perfectly for us.

We have a new bulletproof “How To” for controlling MyQ garage door openers.
http://www.007systems.com/blog/how-to-automate-your-chamberlain-or-liftmaster-myq-garage-door-opener-with-home-automation-controller-like-the-vera