{"action":"created","comment":{"url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/comments/85687967","pull_request_review_id":6387354,"id":85687967,"diff_hunk":"@@ -1,100 +1,449 @@\n \"\"\"\n-Support for iCloud connected devices.\n+Platform that supports scanning iCloud.\n \n For more details about this platform, please refer to the documentation at\n https://home-assistant.io/components/device_tracker.icloud/\n \"\"\"\n import logging\n+import random\n+import os\n+\n import voluptuous as vol\n \n-from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME,\n-                                 EVENT_HOMEASSISTANT_START)\n+from homeassistant.const import CONF_USERNAME, CONF_PASSWORD\n+from homeassistant.components.device_tracker import (\n+    PLATFORM_SCHEMA, DOMAIN, ATTR_ATTRIBUTES, ENTITY_ID_FORMAT)\n+from homeassistant.components.zone import active_zone\n from homeassistant.helpers.event import track_utc_time_change\n+import homeassistant.helpers.config_validation as cv\n from homeassistant.util import slugify\n-from homeassistant.components.device_tracker import (ENTITY_ID_FORMAT,\n-                                                     PLATFORM_SCHEMA)\n+import homeassistant.util.dt as dt_util\n+from homeassistant.util.location import distance\n+from homeassistant.loader import get_component\n \n _LOGGER = logging.getLogger(__name__)\n \n REQUIREMENTS = ['pyicloud==0.9.1']\n \n-CONF_INTERVAL = 'interval'\n-KEEPALIVE_INTERVAL = 4\n+CONF_IGNORED_DEVICES = 'ignored_devices'\n+CONF_GMTT = 'google_maps_travel_time'\n+CONF_COOKIEDIRECTORY = 'cookiedirectory'\n+CONF_ACCOUNTNAME = 'account_name'\n+\n+# entity attributes\n+ATTR_ACCOUNTNAME = 'account_name'\n+ATTR_INTERVAL = 'interval'\n+ATTR_DEVICENAME = 'device_name'\n+ATTR_BATTERY = 'battery'\n+ATTR_DISTANCE = 'distance'\n+ATTR_DEVICESTATUS = 'device_status'\n+ATTR_LOWPOWERMODE = 'low_power_mode'\n+ATTR_BATTERYSTATUS = 'battery_status'\n+ATTR_GMTT = 'google_maps_travel_time'\n+ATTR_GMTT_DURATION = 'gmtt_duration'\n+ATTR_GMTT_ORIGIN = 'gmtt_origin'\n+\n+ICLOUDTRACKERS = {}\n+\n+_CONFIGURING = {}\n+\n+DEVICESTATUSSET = ['features', 'maxMsgChar', 'darkWake', 'fmlyShare',\n+                   'deviceStatus', 'remoteLock', 'activationLocked',\n+                   'deviceClass', 'id', 'deviceModel', 'rawDeviceModel',\n+                   'passcodeLength', 'canWipeAfterLock', 'trackingInfo',\n+                   'location', 'msg', 'batteryLevel', 'remoteWipe',\n+                   'thisDevice', 'snd', 'prsId', 'wipeInProgress',\n+                   'lowPowerMode', 'lostModeEnabled', 'isLocating',\n+                   'lostModeCapable', 'mesg', 'name', 'batteryStatus',\n+                   'lockedTimestamp', 'lostTimestamp', 'locationCapable',\n+                   'deviceDisplayName', 'lostDevice', 'deviceColor',\n+                   'wipedTimestamp', 'modelDisplayName', 'locationEnabled',\n+                   'isMac', 'locFoundEnabled']\n+\n+DEVICESTATUSCODES = {'200': 'online', '201': 'offline', '203': 'pending',\n+                     '204': 'unregistered'}\n+\n+SERVICE_SCHEMA = vol.Schema({\n+    vol.Optional(ATTR_ACCOUNTNAME): vol.All(cv.ensure_list, [cv.slugify]),\n+    vol.Optional(ATTR_DEVICENAME): cv.slugify,\n+    vol.Optional(ATTR_INTERVAL): cv.positive_int,\n+})\n \n PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({\n-    vol.Required(CONF_USERNAME): vol.Coerce(str),\n-    vol.Required(CONF_PASSWORD): vol.Coerce(str),\n-    vol.Optional(CONF_INTERVAL, default=8): vol.All(vol.Coerce(int),\n-                                                    vol.Range(min=1))\n-    })\n-\n-\n-def setup_scanner(hass, config, see):\n-    \"\"\"Setup the iCloud Scanner.\"\"\"\n-    from pyicloud import PyiCloudService\n-    from pyicloud.exceptions import PyiCloudFailedLoginException\n-    from pyicloud.exceptions import PyiCloudNoDevicesException\n-    logging.getLogger(\"pyicloud.base\").setLevel(logging.WARNING)\n-\n-    username = config[CONF_USERNAME]\n-    password = config[CONF_PASSWORD]\n-\n-    try:\n-        _LOGGER.info('Logging into iCloud Account')\n-        # Attempt the login to iCloud\n-        api = PyiCloudService(username, password, verify=True)\n-    except PyiCloudFailedLoginException as error:\n-        _LOGGER.exception('Error logging into iCloud Service: %s', error)\n+    vol.Required(CONF_USERNAME): cv.string,\n+    vol.Required(CONF_PASSWORD): cv.string,\n+    vol.Optional(ATTR_ACCOUNTNAME): cv.slugify,\n+    vol.Optional(CONF_GMTT, default={}):\n+        vol.Schema({cv.slugify: cv.entity_id}),\n+})\n+\n+\n+def setup_scanner(hass, config: dict, see):\n+    \"\"\"Set up the iCloud Scanner.\"\"\"\n+    # pylint: disable=too-many-locals\n+    username = config.get(CONF_USERNAME)\n+    password = config.get(CONF_PASSWORD)\n+    account = config.get(CONF_ACCOUNTNAME, slugify(username.partition('@')[0]))\n+\n+    googletraveltime = config.get(CONF_GMTT)\n+\n+    icloudaccount = Icloud(hass, username, password, account, googletraveltime,\n+                           see)\n+    if icloudaccount:\n+        ICLOUDTRACKERS[account] = icloudaccount\n+\n+    else:\n+        _LOGGER.error(\"No ICLOUDTRACKERS added\")\n         return False\n \n-    def keep_alive(now):\n-        \"\"\"Keep authenticating iCloud connection.\n+    def lost_iphone(call):\n+        \"\"\"Call the lost iphone function if the device is found.\"\"\"\n+        accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS)\n+        devicename = call.data.get(ATTR_DEVICENAME)\n+        for account in accounts:\n+            if account in ICLOUDTRACKERS:\n+                ICLOUDTRACKERS[account].lost_iphone(devicename)\n+    hass.services.register(DOMAIN, 'icloud_lost_iphone', lost_iphone,\n+                           schema=SERVICE_SCHEMA)\n \n-        The session timeouts if we are not using it so we\n-        have to re-authenticate & this will send an email.\n-        \"\"\"\n-        api.authenticate()\n-        _LOGGER.info(\"Authenticate against iCloud\")\n+    def update_icloud(call):\n+        \"\"\"Call the update function of an icloud account.\"\"\"\n+        accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS)\n+        devicename = call.data.get(ATTR_DEVICENAME)\n+        for account in accounts:\n+            if account in ICLOUDTRACKERS:\n+                ICLOUDTRACKERS[account].update_icloud(devicename)\n+    hass.services.register(DOMAIN, 'icloud_update', update_icloud,\n+                           schema=SERVICE_SCHEMA)\n \n-    seen_devices = {}\n+    def reset_account_icloud(call):\n+        \"\"\"Reset an icloud account.\"\"\"\n+        accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS)\n+        for account in accounts:\n+            if account in ICLOUDTRACKERS:\n+                ICLOUDTRACKERS[account].reset_account_icloud()\n+    hass.services.register(DOMAIN, 'icloud_reset_account',\n+                           reset_account_icloud, schema=SERVICE_SCHEMA)\n+\n+    def setinterval(call):\n+        \"\"\"Call the update function of an icloud account.\"\"\"\n+        accounts = call.data.get(ATTR_ACCOUNTNAME, ICLOUDTRACKERS)\n+        interval = call.data.get(ATTR_INTERVAL)\n+        devicename = call.data.get(ATTR_DEVICENAME)\n+        for account in accounts:\n+            if account in ICLOUDTRACKERS:\n+                ICLOUDTRACKERS[account].setinterval(interval, devicename)\n+\n+    hass.services.register(DOMAIN, 'icloud_set_interval', setinterval,\n+                           schema=SERVICE_SCHEMA)\n+\n+    # Tells the bootstrapper that the component was successfully initialized\n+    return True\n+\n+\n+class Icloud(object):  # pylint: disable=too-many-instance-attributes\n+    \"\"\"Represent an icloud account in Home Assistant.\"\"\"\n+\n+    def __init__(self, hass, username, password, name, googletraveltime, see):\n+        \"\"\"Initialize an iCloud account.\"\"\"\n+        # pylint: disable=too-many-arguments,too-many-branches\n+        # pylint: disable=too-many-statements,too-many-locals\n+        self.hass = hass\n+        self.username = username\n+        self.password = password\n+        self.api = None\n+        self.accountname = name\n+        self.devices = {}\n+        self.seen_devices = {}\n+        self.googletraveltime = googletraveltime\n+        self._overridestates = {}\n+        self._intervals = {}\n+        self.see = see\n+\n+        self._trusted_device = None\n+        self._verification_code = None\n+\n+        self._attrs = {}\n+        self._attrs[ATTR_ACCOUNTNAME] = name\n+\n+        self.reset_account_icloud()\n+\n+        randomseconds = random.randint(10, 59)\n+        track_utc_time_change(\n+            self.hass, self.keep_alive,\n+            second=randomseconds\n+        )\n+\n+    def reset_account_icloud(self):\n+        \"\"\"Reset an icloud account.\"\"\"\n+        from pyicloud import PyiCloudService\n+        from pyicloud.exceptions import PyiCloudFailedLoginException\n+        try:\n+            icloud_dir = self.hass.config.path('icloud')\n+            if not os.path.exists(icloud_dir):\n+                os.makedirs(icloud_dir)\n+            self.api = PyiCloudService(\n+                self.username, self.password,\n+                cookie_directory=icloud_dir,\n+                verify=True)\n+            self.devices = {}\n+            self._overridestates = {}\n+            self._intervals = {}\n+            for device in self.api.devices:\n+                status = device.status(DEVICESTATUSSET)\n+                devicename = slugify(status['name'].replace(' ', '', 99))\n+                if devicename not in self.devices:\n+                    self.devices[devicename] = device\n+                    self._intervals[devicename] = 1\n+                    self._overridestates[devicename] = None\n+                    self.update_device(devicename)\n+\n+        except PyiCloudFailedLoginException as error:\n+            _LOGGER.error('Error logging into iCloud Service: %s', error)\n+\n+    def icloud_trusted_device_callback(self, callback_data):\n+        \"\"\"The trusted device is chosen.\"\"\"\n+        self._trusted_device = int(callback_data.get('0', '0'))\n+        self._trusted_device = self.api.trusted_devices[self._trusted_device]\n+        if self.accountname in _CONFIGURING:\n+            request_id = _CONFIGURING.pop(self.accountname)\n+            configurator = get_component('configurator')\n+            configurator.request_done(request_id)\n+\n+    def icloud_need_trusted_device(self):\n+        \"\"\"We need a trusted device.\"\"\"\n+        configurator = get_component('configurator')\n+        if self.accountname in _CONFIGURING:\n+            return\n+\n+        devicesstring = ''\n+        devices = self.api.trusted_devices\n+        for i, device in enumerate(devices):\n+            devicesstring += \"{}: {};\".format(i, device.get('deviceName'))\n+\n+        _CONFIGURING[self.accountname] = configurator.request_config(\n+            self.hass, 'iCloud {}'.format(self.accountname),\n+            self.icloud_trusted_device_callback,\n+            description=(\n+                'Please choose your trusted device by entering'\n+                ' the index from this list: ' + devicesstring),\n+            description_image=\"/static/images/config_icloud.png\",","path":"homeassistant/components/device_tracker/icloud.py","position":268,"original_position":268,"commit_id":"346e30c2fc4133f0d317e0a6d8a82b33a189d55c","original_commit_id":"346e30c2fc4133f0d317e0a6d8a82b33a189d55c","user":{"login":"balloob","id":1444314,"avatar_url":"https://avatars.githubusercontent.com/u/1444314?v=3","gravatar_id":"","url":"https://api.github.com/users/balloob","html_url":"https://github.com/balloob","followers_url":"https://api.github.com/users/balloob/followers","following_url":"https://api.github.com/users/balloob/following{/other_user}","gists_url":"https://api.github.com/users/balloob/gists{/gist_id}","starred_url":"https://api.github.com/users/balloob/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/balloob/subscriptions","organizations_url":"https://api.github.com/users/balloob/orgs","repos_url":"https://api.github.com/users/balloob/repos","events_url":"https://api.github.com/users/balloob/events{/privacy}","received_events_url":"https://api.github.com/users/balloob/received_events","type":"User","site_admin":false},"body":"This should not be `description_image` but instead be `entity_picture`","created_at":"2016-10-31T05:42:43Z","updated_at":"2016-10-31T05:50:14Z","html_url":"https://github.com/home-assistant/home-assistant/pull/4081#discussion_r85687967","pull_request_url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081","_links":{"self":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/comments/85687967"},"html":{"href":"https://github.com/home-assistant/home-assistant/pull/4081#discussion_r85687967"},"pull_request":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081"}}},"pull_request":{"url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081","id":91263085,"html_url":"https://github.com/home-assistant/home-assistant/pull/4081","diff_url":"https://github.com/home-assistant/home-assistant/pull/4081.diff","patch_url":"https://github.com/home-assistant/home-assistant/pull/4081.patch","issue_url":"https://api.github.com/repos/home-assistant/home-assistant/issues/4081","number":4081,"state":"open","locked":false,"title":"Update the icloud device_tracker","user":{"login":"Bart274","id":1118630,"avatar_url":"https://avatars.githubusercontent.com/u/1118630?v=3","gravatar_id":"","url":"https://api.github.com/users/Bart274","html_url":"https://github.com/Bart274","followers_url":"https://api.github.com/users/Bart274/followers","following_url":"https://api.github.com/users/Bart274/following{/other_user}","gists_url":"https://api.github.com/users/Bart274/gists{/gist_id}","starred_url":"https://api.github.com/users/Bart274/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bart274/subscriptions","organizations_url":"https://api.github.com/users/Bart274/orgs","repos_url":"https://api.github.com/users/Bart274/repos","events_url":"https://api.github.com/users/Bart274/events{/privacy}","received_events_url":"https://api.github.com/users/Bart274/received_events","type":"User","site_admin":false},"body":"**Description:**\nThis PR updates the icloud device_tracker with the following changes:\n- Each device has it's own dynamic interval instead of a fixed interval for all devices linked to one account. This interval is based on the location of the device, the distance towards home and the current battery level.\n- A service is added to call for an update once.\n- A service is added to change the interval to a new interval.\n- A service is added to play the Lost iPhone sound on any device.\n- A service is added to reset an account, it will restart the API. This is useful when not all devices are found at startup or when you have added a new device to your account.\n- 2 Factor Authentication has been added to the iCloud tracker. It will ask which trusted device you'll want to use, send the verification code to that device and you'll be able to enter that code in the UI of HASS. Your account would be verified for 2 months (even after restarting HASS).\n\nI closed my old PR https://github.com/home-assistant/home-assistant/pull/3946 to start anew with this PR.\n\n**Example entry for `configuration.yaml` (if applicable):**\n\n``` yaml\ndevice_tracker:\n  - platform: icloud\n    account_name: person1\n    username: <username of person1>\n    password: <password of person1>\n    google_maps_travel_time:\n      iphonebart: sensor.bart_to_home\n  - platform: icloud\n    username: <username of person2>\n    password: <password of person2>\n```\n\n**Checklist:**\n\nIf user exposed functionality or configuration variables are added/changed:\n- [ ] Documentation added/updated in [home-assistant.github.io](https://github.com/home-assistant/home-assistant.github.io)\n","created_at":"2016-10-27T19:17:00Z","updated_at":"2016-10-31T05:50:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8241cc8dea253657787fe4946a4565942e438f98","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081/commits","review_comments_url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081/comments","review_comment_url":"https://api.github.com/repos/home-assistant/home-assistant/pulls/comments{/number}","comments_url":"https://api.github.com/repos/home-assistant/home-assistant/issues/4081/comments","statuses_url":"https://api.github.com/repos/home-assistant/home-assistant/statuses/346e30c2fc4133f0d317e0a6d8a82b33a189d55c","head":{"label":"Bart274:icloud","ref":"icloud","sha":"346e30c2fc4133f0d317e0a6d8a82b33a189d55c","user":{"login":"Bart274","id":1118630,"avatar_url":"https://avatars.githubusercontent.com/u/1118630?v=3","gravatar_id":"","url":"https://api.github.com/users/Bart274","html_url":"https://github.com/Bart274","followers_url":"https://api.github.com/users/Bart274/followers","following_url":"https://api.github.com/users/Bart274/following{/other_user}","gists_url":"https://api.github.com/users/Bart274/gists{/gist_id}","starred_url":"https://api.github.com/users/Bart274/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bart274/subscriptions","organizations_url":"https://api.github.com/users/Bart274/orgs","repos_url":"https://api.github.com/users/Bart274/repos","events_url":"https://api.github.com/users/Bart274/events{/privacy}","received_events_url":"https://api.github.com/users/Bart274/received_events","type":"User","site_admin":false},"repo":{"id":71329112,"name":"home-assistant","full_name":"Bart274/home-assistant","owner":{"login":"Bart274","id":1118630,"avatar_url":"https://avatars.githubusercontent.com/u/1118630?v=3","gravatar_id":"","url":"https://api.github.com/users/Bart274","html_url":"https://github.com/Bart274","followers_url":"https://api.github.com/users/Bart274/followers","following_url":"https://api.github.com/users/Bart274/following{/other_user}","gists_url":"https://api.github.com/users/Bart274/gists{/gist_id}","starred_url":"https://api.github.com/users/Bart274/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bart274/subscriptions","organizations_url":"https://api.github.com/users/Bart274/orgs","repos_url":"https://api.github.com/users/Bart274/repos","events_url":"https://api.github.com/users/Bart274/events{/privacy}","received_events_url":"https://api.github.com/users/Bart274/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Bart274/home-assistant","description":":house_with_garden: Open-source home automation platform running on Python 3","fork":true,"url":"https://api.github.com/repos/Bart274/home-assistant","forks_url":"https://api.github.com/repos/Bart274/home-assistant/forks","keys_url":"https://api.github.com/repos/Bart274/home-assistant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Bart274/home-assistant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Bart274/home-assistant/teams","hooks_url":"https://api.github.com/repos/Bart274/home-assistant/hooks","issue_events_url":"https://api.github.com/repos/Bart274/home-assistant/issues/events{/number}","events_url":"https://api.github.com/repos/Bart274/home-assistant/events","assignees_url":"https://api.github.com/repos/Bart274/home-assistant/assignees{/user}","branches_url":"https://api.github.com/repos/Bart274/home-assistant/branches{/branch}","tags_url":"https://api.github.com/repos/Bart274/home-assistant/tags","blobs_url":"https://api.github.com/repos/Bart274/home-assistant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Bart274/home-assistant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Bart274/home-assistant/git/refs{/sha}","trees_url":"https://api.github.com/repos/Bart274/home-assistant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Bart274/home-assistant/statuses/{sha}","languages_url":"https://api.github.com/repos/Bart274/home-assistant/languages","stargazers_url":"https://api.github.com/repos/Bart274/home-assistant/stargazers","contributors_url":"https://api.github.com/repos/Bart274/home-assistant/contributors","subscribers_url":"https://api.github.com/repos/Bart274/home-assistant/subscribers","subscription_url":"https://api.github.com/repos/Bart274/home-assistant/subscription","commits_url":"https://api.github.com/repos/Bart274/home-assistant/commits{/sha}","git_commits_url":"https://api.github.com/repos/Bart274/home-assistant/git/commits{/sha}","comments_url":"https://api.github.com/repos/Bart274/home-assistant/comments{/number}","issue_comment_url":"https://api.github.com/repos/Bart274/home-assistant/issues/comments{/number}","contents_url":"https://api.github.com/repos/Bart274/home-assistant/contents/{+path}","compare_url":"https://api.github.com/repos/Bart274/home-assistant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Bart274/home-assistant/merges","archive_url":"https://api.github.com/repos/Bart274/home-assistant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Bart274/home-assistant/downloads","issues_url":"https://api.github.com/repos/Bart274/home-assistant/issues{/number}","pulls_url":"https://api.github.com/repos/Bart274/home-assistant/pulls{/number}","milestones_url":"https://api.github.com/repos/Bart274/home-assistant/milestones{/number}","notifications_url":"https://api.github.com/repos/Bart274/home-assistant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Bart274/home-assistant/labels{/name}","releases_url":"https://api.github.com/repos/Bart274/home-assistant/releases{/id}","deployments_url":"https://api.github.com/repos/Bart274/home-assistant/deployments","created_at":"2016-10-19T07:10:43Z","updated_at":"2016-10-19T07:10:46Z","pushed_at":"2016-10-30T19:44:40Z","git_url":"git://github.com/Bart274/home-assistant.git","ssh_url":"git@github.com:Bart274/home-assistant.git","clone_url":"https://github.com/Bart274/home-assistant.git","svn_url":"https://github.com/Bart274/home-assistant","homepage":"https://home-assistant.io","size":42761,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"home-assistant:dev","ref":"dev","sha":"09db875acef2460a23199bd1a3b367e0c8bf1d72","user":{"login":"home-assistant","id":13844975,"avatar_url":"https://avatars.githubusercontent.com/u/13844975?v=3","gravatar_id":"","url":"https://api.github.com/users/home-assistant","html_url":"https://github.com/home-assistant","followers_url":"https://api.github.com/users/home-assistant/followers","following_url":"https://api.github.com/users/home-assistant/following{/other_user}","gists_url":"https://api.github.com/users/home-assistant/gists{/gist_id}","starred_url":"https://api.github.com/users/home-assistant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/home-assistant/subscriptions","organizations_url":"https://api.github.com/users/home-assistant/orgs","repos_url":"https://api.github.com/users/home-assistant/repos","events_url":"https://api.github.com/users/home-assistant/events{/privacy}","received_events_url":"https://api.github.com/users/home-assistant/received_events","type":"Organization","site_admin":false},"repo":{"id":12888993,"name":"home-assistant","full_name":"home-assistant/home-assistant","owner":{"login":"home-assistant","id":13844975,"avatar_url":"https://avatars.githubusercontent.com/u/13844975?v=3","gravatar_id":"","url":"https://api.github.com/users/home-assistant","html_url":"https://github.com/home-assistant","followers_url":"https://api.github.com/users/home-assistant/followers","following_url":"https://api.github.com/users/home-assistant/following{/other_user}","gists_url":"https://api.github.com/users/home-assistant/gists{/gist_id}","starred_url":"https://api.github.com/users/home-assistant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/home-assistant/subscriptions","organizations_url":"https://api.github.com/users/home-assistant/orgs","repos_url":"https://api.github.com/users/home-assistant/repos","events_url":"https://api.github.com/users/home-assistant/events{/privacy}","received_events_url":"https://api.github.com/users/home-assistant/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/home-assistant/home-assistant","description":":house_with_garden: Open-source home automation platform running on Python 3","fork":false,"url":"https://api.github.com/repos/home-assistant/home-assistant","forks_url":"https://api.github.com/repos/home-assistant/home-assistant/forks","keys_url":"https://api.github.com/repos/home-assistant/home-assistant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/home-assistant/home-assistant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/home-assistant/home-assistant/teams","hooks_url":"https://api.github.com/repos/home-assistant/home-assistant/hooks","issue_events_url":"https://api.github.com/repos/home-assistant/home-assistant/issues/events{/number}","events_url":"https://api.github.com/repos/home-assistant/home-assistant/events","assignees_url":"https://api.github.com/repos/home-assistant/home-assistant/assignees{/user}","branches_url":"https://api.github.com/repos/home-assistant/home-assistant/branches{/branch}","tags_url":"https://api.github.com/repos/home-assistant/home-assistant/tags","blobs_url":"https://api.github.com/repos/home-assistant/home-assistant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/home-assistant/home-assistant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/home-assistant/home-assistant/git/refs{/sha}","trees_url":"https://api.github.com/repos/home-assistant/home-assistant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/home-assistant/home-assistant/statuses/{sha}","languages_url":"https://api.github.com/repos/home-assistant/home-assistant/languages","stargazers_url":"https://api.github.com/repos/home-assistant/home-assistant/stargazers","contributors_url":"https://api.github.com/repos/home-assistant/home-assistant/contributors","subscribers_url":"https://api.github.com/repos/home-assistant/home-assistant/subscribers","subscription_url":"https://api.github.com/repos/home-assistant/home-assistant/subscription","commits_url":"https://api.github.com/repos/home-assistant/home-assistant/commits{/sha}","git_commits_url":"https://api.github.com/repos/home-assistant/home-assistant/git/commits{/sha}","comments_url":"https://api.github.com/repos/home-assistant/home-assistant/comments{/number}","issue_comment_url":"https://api.github.com/repos/home-assistant/home-assistant/issues/comments{/number}","contents_url":"https://api.github.com/repos/home-assistant/home-assistant/contents/{+path}","compare_url":"https://api.github.com/repos/home-assistant/home-assistant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/home-assistant/home-assistant/merges","archive_url":"https://api.github.com/repos/home-assistant/home-assistant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/home-assistant/home-assistant/downloads","issues_url":"https://api.github.com/repos/home-assistant/home-assistant/issues{/number}","pulls_url":"https://api.github.com/repos/home-assistant/home-assistant/pulls{/number}","milestones_url":"https://api.github.com/repos/home-assistant/home-assistant/milestones{/number}","notifications_url":"https://api.github.com/repos/home-assistant/home-assistant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/home-assistant/home-assistant/labels{/name}","releases_url":"https://api.github.com/repos/home-assistant/home-assistant/releases{/id}","deployments_url":"https://api.github.com/repos/home-assistant/home-assistant/deployments","created_at":"2013-09-17T07:29:48Z","updated_at":"2016-10-31T05:13:27Z","pushed_at":"2016-10-31T04:51:03Z","git_url":"git://github.com/home-assistant/home-assistant.git","ssh_url":"git@github.com:home-assistant/home-assistant.git","clone_url":"https://github.com/home-assistant/home-assistant.git","svn_url":"https://github.com/home-assistant/home-assistant","homepage":"https://home-assistant.io","size":84829,"stargazers_count":4442,"watchers_count":4442,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1157,"mirror_url":null,"open_issues_count":329,"forks":1157,"open_issues":329,"watchers":4442,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081"},"html":{"href":"https://github.com/home-assistant/home-assistant/pull/4081"},"issue":{"href":"https://api.github.com/repos/home-assistant/home-assistant/issues/4081"},"comments":{"href":"https://api.github.com/repos/home-assistant/home-assistant/issues/4081/comments"},"review_comments":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081/comments"},"review_comment":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/home-assistant/home-assistant/pulls/4081/commits"},"statuses":{"href":"https://api.github.com/repos/home-assistant/home-assistant/statuses/346e30c2fc4133f0d317e0a6d8a82b33a189d55c"}}}}
{"actor":{"display_login":"balloob"}}