Advertisement
Guest User

MyQ Home-Assistant Cover 0.2

a guest
Aug 29th, 2016
898
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.26 KB | None | 0 0
  1. """
  2. Support for MyQ garage doors.
  3.  
  4. For more details about this platform, please refer to the documentation at
  5. https://home-assistant.io/components/cover.myq/
  6. """
  7.  
  8. import logging
  9. import requests
  10.  
  11. from homeassistant.components.cover import CoverDevice
  12. from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, CONF_NAME, STATE_OPEN, STATE_CLOSED
  13.  
  14.  
  15. DEPENDENCIES = []
  16.  
  17. CONF_BRAND = 'brand'
  18.  
  19. LIFTMASTER = 'liftmaster'
  20. CHAMBERLAIN = 'chamberlain'
  21. CRAFTMASTER = 'craftmaster'
  22.  
  23. SUPPORTED_BRANDS = [LIFTMASTER, CHAMBERLAIN, CRAFTMASTER]
  24.  
  25. DEFAULT_BRAND = CHAMBERLAIN
  26. DEFAULT_NAME = "MyQ"
  27.  
  28. APP_ID = 'app_id'
  29. HOST_URI = 'host_uri'
  30.  
  31. BRAND_MAPPINGS = {
  32.     LIFTMASTER: {
  33.         APP_ID: 'JVM/G9Nwih5BwKgNCjLxiFUQxQijAebyyg8QUHr7JOrP+tuPb8iHfRHKwTmDzHOu',
  34.         HOST_URI: 'myqexternal.myqdevice.com'
  35.     },
  36.     CHAMBERLAIN: {
  37.         APP_ID: 'Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB%2Fi',
  38.         HOST_URI: 'myqexternal.myqdevice.com'
  39.     },
  40.     CRAFTMASTER: {
  41.         APP_ID: 'eU97d99kMG4t3STJZO/Mu2wt69yTQwM0WXZA5oZ74/ascQ2xQrLD/yjeVhEQccBZ',
  42.         HOST_URI: 'craftexternal.myqdevice.com'
  43.     }
  44. }
  45.  
  46. def setup_platform(hass, config, add_devices, discovery_info=None):
  47.     """Set up the MyQ garage door."""
  48.  
  49.     name = config.get(CONF_NAME) if \
  50.         CONF_NAME else DEFAULT_NAME
  51.  
  52.     username = config.get(CONF_USERNAME)
  53.     password = config.get(CONF_PASSWORD)
  54.  
  55.     logger = logging.getLogger(__name__)
  56.  
  57.     if username is None or password is None:
  58.         logger.error("MyQ Cover - Missing username or password.")
  59.         return
  60.  
  61.     try:
  62.         brand = BRAND_MAPPINGS[config.get(CONF_BRAND)];
  63.     except KeyError:
  64.         logger.error("MyQ Cover - Missing or unsupported brand. Supported brands: %s", ', '.join(SUPPORTED_BRANDS))
  65.         return
  66.  
  67.     myq = MyQAPI(username, password, brand, logger)
  68.  
  69.     add_devices(MyQCoverDevice(myq, door, name) for door
  70.                 in myq.get_garage_doors())
  71.  
  72.  
  73. class MyQAPI(object):
  74.     """Class for interacting with the MyQ iOS App API."""
  75.  
  76.     LOCALE = "en"
  77.     LOGIN_ENDPOINT = "Membership/ValidateUserWithCulture"
  78.     DEVICE_LIST_ENDPOINT = "api/UserDeviceDetails"
  79.     DEVICE_SET_ENDPOINT = "Device/setDeviceAttribute"
  80.     DEVICE_STATUS_ENDPOINT = "/Device/getDeviceAttribute"
  81.  
  82.     DOOR_STATE = {
  83.         '1': STATE_OPEN, #'open',
  84.         '2': STATE_CLOSED, #'close',
  85.         '4': STATE_OPEN, #'opening',
  86.         '5': STATE_CLOSED, #'closing',
  87.         '8': STATE_OPEN, #'in_transition',
  88.         '9': STATE_OPEN, #'open'
  89.     }
  90.  
  91.     def __init__(self, username, password, brand, logger):
  92.         """Initialize the API object."""
  93.         self.username = username
  94.         self.password = password
  95.         self.brand = brand
  96.         self._logger = logger;
  97.  
  98.         self.security_token = None
  99.         self._logged_in = False
  100.  
  101.     def login(self):
  102.         """Log in to the MyQ service."""
  103.  
  104.         params = {
  105.             'username': self.username,
  106.             'password': self.password,
  107.             'appId': self.brand[APP_ID],
  108.             'culture': self.LOCALE
  109.         }
  110.  
  111.         login = requests.get(
  112.             'https://{host_uri}/{login_endpoint}'.format(
  113.                 host_uri=self.brand[HOST_URI],
  114.                 login_endpoint=self.LOGIN_ENDPOINT),
  115.             params=params)
  116.         auth = login.json()
  117.         self.security_token = auth['SecurityToken']
  118.         self._logger.debug('Logged in to MyQ API')
  119.         return True
  120.  
  121.     def get_devices(self):
  122.         """List all MyQ devices."""
  123.  
  124.         if not self._logged_in:
  125.             self._logged_in = self.login()
  126.  
  127.         params = {
  128.             'appId': self.brand[APP_ID],
  129.             'securityToken': self.security_token
  130.         }
  131.  
  132.         devices = requests.get(
  133.             'https://{host_uri}/{device_list_endpoint}'.format(
  134.                 host_uri=self.brand[HOST_URI],
  135.                 device_list_endpoint=self.DEVICE_LIST_ENDPOINT),
  136.             params=params)
  137.  
  138.         devices = devices.json()['Devices']
  139.  
  140.         return devices
  141.  
  142.     def get_garage_doors(self):
  143.         """List only MyQ garage door devices."""
  144.  
  145.         devices = self.get_devices()
  146.  
  147.         garage_doors = []
  148.  
  149.         for device in devices:
  150.             if device['MyQDeviceTypeName'] == 'GarageDoorOpener':
  151.                  garage_doors.append(device['DeviceId'])
  152. # This looks like it expects a generic garage door operer name
  153. #                for attribute in device['Attributes']:
  154. #                    if attribute['AttributeDisplayName'] == 'desc' and \
  155. #                            attribute['Value'] == 'Garage Door Opener':
  156. #                        garage_doors.append(device['DeviceId'])
  157.  
  158.         return garage_doors
  159.  
  160.     def get_status(self, device_id):
  161.         """Get device status."""
  162.  
  163.         params = {
  164.             'appId': self.brand[APP_ID],
  165.             'securityToken': self.security_token,
  166.             'devId': device_id,
  167.             'name': 'doorstate',
  168.         }
  169.  
  170.         device_status = requests.get(
  171.             'https://{host_uri}/{device_status_endpoint}'.format(
  172.                 host_uri=self.brand[HOST_URI],
  173.                 device_status_endpoint=self.DEVICE_STATUS_ENDPOINT),
  174.             params=params)
  175.  
  176.         attval = device_status.json()['AttributeValue']
  177.  
  178.         garage_state = self.DOOR_STATE[attval]
  179.         return garage_state
  180.  
  181.     def close_device(self, device_id):
  182.         """Close MyQ Device."""
  183.         return self.set_state(device_id, '0')
  184.  
  185.     def open_device(self, device_id):
  186.         """Open MyQ Device."""
  187.         return self.set_state(device_id, '1')
  188.  
  189.  
  190.     def set_state(self, device_id, state):
  191.         """Set device state."""
  192.         payload = {
  193.             'AttributeName': 'desireddoorstate',
  194.             'DeviceId': device_id,
  195.             'ApplicationId': self.brand[APP_ID],
  196.             'AttributeValue': state,
  197.             'SecurityToken': self.security_token,
  198.         }
  199.         device_action = requests.put(
  200.             'https://{host_uri}/{device_set_endpoint}'.format(
  201.                 host_uri=self.brand[HOST_URI],
  202.                 device_set_endpoint=self.DEVICE_SET_ENDPOINT),
  203.             data=payload)
  204.  
  205.         return device_action.status_code == 200
  206.  
  207.  
  208. class MyQCoverDevice(CoverDevice):
  209.     """Representation of a MyQ cover."""
  210.  
  211.     def __init__(self, myq, device_id, name):
  212.         """Initialize with API object, device id, and name."""
  213.         self.myq = myq
  214.         self.device_id = device_id
  215.         self._name = name
  216.  
  217.     @property
  218.     def should_poll(self):
  219.         """Poll for state."""
  220.         return True
  221.  
  222.     @property
  223.     def name(self):
  224.         """Return the name of the garage door if any."""
  225.         return self._name if self._name else DEFAULT_NAME
  226.  
  227.     @property
  228.     def is_closed(self):
  229.         """Return True if cover is closed, else False."""
  230.         status = self.myq.get_status(self.device_id)
  231.         return status == STATE_CLOSED
  232.  
  233.     @property
  234.     def current_cover_position(self):
  235.         """Return current position of cover."""
  236.         return 0 if self.is_closed else 100
  237.  
  238.     def close_cover(self):
  239.         """Issue close command to cover."""
  240.         self.myq.close_device(self.device_id)
  241.  
  242.     def open_cover(self):
  243.         """Issue open command to cover."""
  244.         self.myq.open_device(self.device_id)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement