MyQ Integration

Here is what I have been using for the past few months to integrate with my MyQ garage door opener. This script is not optimized, but it works well for me, and I am lazy…

Put this script in a package called myq. Enclosed is a reference tag implementation. You will have to make an instance of the tag, and set the device parameter equal to your devices serial number.

tags.json (6.0 KB)

Script

class MyQ():
	
	#This appid can be anything.... i believe
	appId =  'Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i'
	agent = 'myQ/19569 CFNetwork/1107.1 Darwin/19.0.0'
	username = "yourmyqusername"
	password = "yourmyqpassword"
	apiVersion = 5
	endpoint = 'https://api.myqdevice.com/api/v{}'.format(apiVersion)
	client = system.net.httpClient()
	security_token = None
	accountId = None
	LOG = system.util.getLogger("com.thundranos.myq")
	last_update = system.date.fromMillis(0)
	status_code = None
	
	headers = {
	  "Content-Type": "application/json",
	  "User-Agent": agent,
	  "ApiVersion": 5,
	  "BrandId": "2",
	  "Culture": "en",
	  "MyQApplicationId": appId,
	  "SecurityToken": ""
	};
	
	def login(self,username=None,password=None,force = False):
		if username:
			self.username = username
		if password:
			self.password = password
		if not self.security_token or force:
			if self.username and self.password:
				url = self.endpoint + "/Login"
				response = self.client.post(url = url, data = {"UserName":self.username,"Password":self.password},headers=self.headers)
				self.status_code = response.statusCode
				if response.statusCode == 200:
					self.security_token = response.getJson()["SecurityToken"]
					self.headers['SecurityToken'] = response.getJson()["SecurityToken"]
					self.getAccountId()
		
	def getAccountId(self):
		if not self.accountId:
			url = self.endpoint + "/My?expand=account"
			response = self.client.get(url = url,headers=self.headers)
			self.status_code = response.statusCode
			if response.statusCode == 200:
				self.accountId = response.json["Account"]["Id"]
			
	def getSecurityToken(self):
		return self.security_token
			
	def updateState(self):
		if self.status_code != 200:
			self.login()
		if self.security_token and self.accountId:
			url = self.endpoint + '.1/Accounts/{}/Devices'.format(self.accountId)
			response = self.client.get(url = url,headers=self.headers)
			self.status_code = response.statusCode
			state = {}
			for item in response.json["items"]:
				state[str(item["serial_number"])] = item
			self.state = state
			self.last_update = system.date.now()
	
	def getState(self,device=None,state=None,force = False):
		if force or system.date.secondsBetween(self.last_update,system.date.now())>60:
			self.updateState()
		if device:
			if state:
				return self.state[device]["state"][state]
			return self.state[device]
		return self.state
		
	def setDoorState(self,device,state):
		data = {"action_type":"open" if state else "close"}
		self.LOG.info('device:{} state:{}'.format(device,state))
		if self.status_code != 200:
			self.login()
		if self.security_token and self.accountId:
			self.LOG.info("here")
			url = self.endpoint + '.1/Accounts/{}/Devices/{}/actions'.format(self.accountId,device)
			response = self.client.put(url=url, data=data, headers=self.headers)

myq = MyQ()

So, to get started, you will want to find the serial number of your myq device, in the resulting JSON from the following. You will see numerous devices listed including the gateway and the door opener. You will need to note the serial number.

myq.myq.login()
myq.myq.getState()

For the tag bindings, I do the following. This will give me the door value. For the scan rate, we check every second. Internally, the script will update every 60 seconds, unless force is set to true, then it will update every time the function is called. At home, I have the scan tag true for 30s after any action, for higher speed querying.

runScript("myq.myq.getState",1000,"yourserialnumber","door_state",{[.]../../metadata/scan})

To open or close the door, invoke the following script.

myq.myq.setDoorState("yourdeviceserialnumber",desiredstate)

Where desiredstate
False = close
True = open

8 Likes

Just a heads up, looks like MyQ broke their api on an update from 4 to 5 today. Working on fixing the script to continue working with the MyQ openers

Updated to work with v5 of the API.

2 Likes

first off, thank you.

Could you dummy this down? I can’t seem to get the tags implemented properly. I can set a button to open my garage doors, but I had to remove the ‘runScript’ and just use

door = system.tag.read("[default]MyQ/Door 2").value # read door serial id
myq.myq.setDoorState(door,1)

This works, but I am struggling with your implementation.

Did you try the included tag import in the first post? That is what I am currently using. It provides tags that shows door status and provide two cmnd tags, to open and close the door.

If you are using a Python script and not an expression, you will have to remove run script.

Take a look at the included tags.