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.

Hey Kyle,

So I tried importing the code and also imported the tags. But I keep getting an error for the tags. I have also set the “device” parameter to the “Serial number” I was able to extract from the MyQ app.
I keep seeing an “Error_ExpressionEval” for all tags. Can anyone please help?

Kyle,

Are you still using this implementation? I’m new to Ignition, so that’s a challenge in itself, however, if I’m running the script correctly in Script Console, I don’t get any return data from myq.myq.login();. All i get is ">>> "

I appreciate any help you can offer.

Hi Todd,

I was looking into this code yesterday to control my garage door and it appears to be returning an error message of 400 during the getAccountId() call. I did some digging on the web and it appears that Chamberlain may have modified their interface such that this particular method is no longer supported. I was able to do a little with IFTTT in order to close the garage door and monitor the states, but I don’t think that is of much help to Ignition (or perhaps it is). I was able to find some python code on GitHub that might use a different ‘hook’ into the MyQ controller, but haven’t had a chance to test it.

TLDR: I don’t believe the method from 2020 will work with the current (2022) MyQ code. I am happy to be wrong if anyone has it working.

I have an old MyQ setup I was considering installing, but I’m wondering if it’s even worth it with the relatively closed architecture. It seems like there are plenty of people using Shelly relays, Arduinos, or similar cheap PLCs/relays to derive garage door telemetry and issue commands.

Hi All,
We will have a new integration with a new module posted in the coming weeks.

Thanks.

2 Likes