diff --git a/august/activity.py b/august/activity.py index 25ecf6f..ab4d913 100644 --- a/august/activity.py +++ b/august/activity.py @@ -1,11 +1,35 @@ from datetime import datetime from enum import Enum +from august.lock import LockDoorStatus, LockStatus + +ACTION_LOCK_ONETOUCHLOCK = "onetouchlock" +ACTION_LOCK_LOCK = "lock" +ACTION_LOCK_UNLOCK = "unlock" +ACTION_DOOR_OPEN = "dooropen" +ACTION_DOOR_CLOSED = "doorclosed" +ACTION_DOORBELL_CALL_INITIATED = "doorbell_call_initiated" +ACTION_DOORBELL_MOTION_DETECTED = "doorbell_motion_detected" +ACTION_DOORBELL_CALL_MISSED = "doorbell_call_missed" +ACTION_DOORBELL_CALL_HANGUP = "doorbell_call_hangup" + +ACTIVITY_ACTIONS_DOORBELL_DING = [ACTION_DOORBELL_CALL_MISSED, ACTION_DOORBELL_CALL_HANGUP] +ACTIVITY_ACTIONS_DOORBELL_MOTION = [ACTION_DOORBELL_MOTION_DETECTED] +ACTIVITY_ACTIONS_DOORBELL_VIEW = [ACTION_DOORBELL_CALL_INITIATED] +ACTIVITY_ACTIONS_LOCK_OPERATION = [ACTION_LOCK_LOCK, ACTION_LOCK_UNLOCK, ACTION_LOCK_ONETOUCHLOCK] +ACTIVITY_ACTIONS_DOOR_OPERATION = [ACTION_DOOR_CLOSED, ACTION_DOOR_OPEN] + +ACTIVITY_ACTION_STATES = { + ACTION_LOCK_ONETOUCHLOCK: LockStatus.LOCKED, + ACTION_LOCK_LOCK: LockStatus.LOCKED, + ACTION_LOCK_UNLOCK: LockStatus.UNLOCKED, + ACTION_DOOR_OPEN: LockDoorStatus.OPEN, + ACTION_DOOR_CLOSED: LockDoorStatus.CLOSED, +} def epoch_to_datetime(epoch): return datetime.fromtimestamp(int(epoch) / 1000.0) - class ActivityType(Enum): DOORBELL_MOTION = "doorbell_motion" DOORBELL_DING = "doorbell_ding" diff --git a/august/api.py b/august/api.py index 287383b..1cc2b98 100644 --- a/august/api.py +++ b/august/api.py @@ -1,25 +1,18 @@ import logging import time -from requests import request, Session - -from august.activity import ( - DoorbellDingActivity, - DoorbellMotionActivity, - DoorbellViewActivity, - LockOperationActivity, - DoorOperationActivity -) -from august.doorbell import ( - Doorbell, - DoorbellDetail -) -from august.lock import ( - Lock, - LockDetail, - LockDoorStatus, - LockStatus, -) +from requests import Session, request + +from august.activity import (ACTIVITY_ACTIONS_DOOR_OPERATION, + ACTIVITY_ACTIONS_DOORBELL_DING, + ACTIVITY_ACTIONS_DOORBELL_MOTION, + ACTIVITY_ACTIONS_DOORBELL_VIEW, + ACTIVITY_ACTIONS_LOCK_OPERATION, + DoorbellDingActivity, DoorbellMotionActivity, + DoorbellViewActivity, DoorOperationActivity, + LockOperationActivity) +from august.doorbell import Doorbell, DoorbellDetail +from august.lock import Lock, LockDetail, LockDoorStatus, LockStatus from august.pin import Pin HEADER_ACCEPT_VERSION = "Accept-Version" @@ -193,15 +186,15 @@ def get_house_activities(self, access_token, house_id, limit=8): for activity_json in response.json(): action = activity_json.get("action") - if action in ["doorbell_call_missed", "doorbell_call_hangup"]: + if action in ACTIVITY_ACTIONS_DOORBELL_DING: activities.append(DoorbellDingActivity(activity_json)) - elif action == "doorbell_motion_detected": + elif action in ACTIVITY_ACTIONS_DOORBELL_MOTION: activities.append(DoorbellMotionActivity(activity_json)) - elif action == "doorbell_call_initiated": + elif action in ACTIVITY_ACTIONS_DOORBELL_VIEW: activities.append(DoorbellViewActivity(activity_json)) - elif action in ["lock", "unlock", "onetouchlock"]: + elif action in ACTIVITY_ACTIONS_LOCK_OPERATION: activities.append(LockOperationActivity(activity_json)) - elif action in ["doorclosed", "dooropen"]: + elif action in ACTIVITY_ACTIONS_DOOR_OPERATION: activities.append(DoorOperationActivity(activity_json)) return activities diff --git a/august/authenticator.py b/august/authenticator.py index 4671c8c..c3c7f48 100644 --- a/august/authenticator.py +++ b/august/authenticator.py @@ -8,6 +8,7 @@ import dateutil.parser import requests + from august.api import HEADER_AUGUST_ACCESS_TOKEN # The default time before expiration to refresh a token diff --git a/known_activities.md b/known_activities.md new file mode 100644 index 0000000..562227f --- /dev/null +++ b/known_activities.md @@ -0,0 +1,215 @@ +# Known Activity Actions + +## doorclosed +``` +{ + "entities": { + "device": "", + "callingUser": "deleted", + "otherUser": "deleted", + "house": "", + "activity": "" + }, + "house": { + "houseID": "", + "houseName": "" + }, + "dateTime": , + "action": "doorclosed", + "deviceName": "", + "deviceID": "", + "deviceType": "lock", + "callingUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "otherUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "info": { + "DateLogActionID": "" + } +} +``` +## dooropen + +``` +{ + "entities": { + "device": "", + "callingUser": "deleted", + "otherUser": "deleted", + "house": "", + "activity": "" + }, + "house": { + "houseID": "", + "houseName": + }, + "dateTime": , + "action": "dooropen", + "deviceName": , + "deviceID": "", + "deviceType": "lock", + "callingUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "otherUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "info": { + "DateLogActionID": "" + } +} +``` + +## unlock + +``` +{ + "entities": { + "device": "", + "callingUser": "", + "otherUser": "deleted", + "house": "", + "activity": "" + }, + "house": { + "houseID": "", + "houseName": + }, + "source": { + "sourceType": "mercury" + }, + "dateTime": , + "action": "unlock", + "deviceName": , + "deviceID": "", + "deviceType": "lock", + "callingUser": { + "UserID": "", + "FirstName": "", + "LastName": "", + "imageInfo": { + "original": { + "width": , + "height": , + "format": "", + "url": "", + "secure_url": "" + }, + "thumbnail": { + "width": , + "height": , + "format": "", + "url": "", + "secure_url": "" + } + } + }, + "otherUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "info": { + "agent": "mercury", + "keypad": true + } +} +``` + +## lock + +``` +{ + "entities": { + "device": "", + "callingUser": "", + "otherUser": "deleted", + "house": "", + "activity": "" + }, + "house": { + "houseID": "", + "houseName": + }, + "dateTime": , + "action": "lock", + "deviceName": , + "deviceID": "", + "deviceType": "lock", + "callingUser": { + "UserID": "", + "FirstName": "", + "LastName": "" + }, + "otherUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "info": { + "remote": true, + "DateLogActionID": "" + } +} +``` +## onetouchlock + +``` +{ + "entities": { + "device": "", + "callingUser": "deleted", + "otherUser": "deleted", + "house": "", + "activity": "" + }, + "house": { + "houseID": "", + "houseName": + }, + "dateTime": , + "action": "onetouchlock", + "deviceName": , + "deviceID": "", + "deviceType": "lock", + "callingUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "otherUser": { + "UserID": "deleted", + "FirstName": "Unknown", + "LastName": "User", + "UserName": "deleteduser", + "PhoneNo": "deleted" + }, + "info": { + "DateLogActionID": "" + } +} +``` diff --git a/tests/fixtures/get_house_activities.json b/tests/fixtures/get_house_activities.json new file mode 100644 index 0000000..083ec0f --- /dev/null +++ b/tests/fixtures/get_house_activities.json @@ -0,0 +1,364 @@ +[ + { + "action" : "lock", + "callingUser" : { + "FirstName" : "MockHouse", + "LastName" : "House", + "UserID" : "mockUserId2" + }, + "dateTime" : 1234, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseTDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "mockActivity2", + "callingUser" : "mockUserId2", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "unlock", + "callingUser" : { + "FirstName" : "MockHouse", + "LastName" : "House", + "UserID" : "mockUserId2" + }, + "dateTime" : 45454, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseXDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "ActivityId", + "callingUser" : "mockUserId2", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "lock", + "callingUser" : { + "FirstName" : "MockHouse", + "LastName" : "House", + "UserID" : "mockUserId2" + }, + "dateTime" : 12345, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseRdoor", + "deviceType" : "lock", + "entities" : { + "activity" : "Activity", + "callingUser" : "mockUserId2", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "unlock", + "callingUser" : { + "FirstName" : "MockHouse", + "LastName" : "House", + "UserID" : "mockUserId2" + }, + "dateTime" : 5678, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseYDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "Activity", + "callingUser" : "mockUserId2", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "lock", + "callingUser" : { + "FirstName" : "MockHouse", + "LastName" : "House", + "UserID" : "mockUserId2" + }, + "dateTime" : 114334, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseQDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "Activity", + "callingUser" : "mockUserId2", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "doorclosed", + "callingUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + }, + "dateTime" : 545454, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouse Tech Room Door", + "deviceType" : "lock", + "entities" : { + "activity" : "activityId", + "callingUser" : "deleted", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time" + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "dooropen", + "callingUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + }, + "dateTime" : 5454, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouse Tech Room Door", + "deviceType" : "lock", + "entities" : { + "activity" : "ActivityId", + "callingUser" : "deleted", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time" + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "doorclosed", + "callingUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + }, + "dateTime" : 545435, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouse Tech Room Door", + "deviceType" : "lock", + "entities" : { + "activity" : "ActivityId", + "callingUser" : "deleted", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDeviceId2+Time" + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + }, + { + "action" : "unlock", + "callingUser" : { + "FirstName" : "mockFirstName", + "LastName" : "mockLastName", + "UserID" : "MockUserId", + "imageInfo" : { + "original" : { + "format" : "jpg", + "height" : 7, + "secure_url" : "mockurl", + "url" : "mockurl", + "width" : 7 + }, + "thumbnail" : { + "format" : "jpg", + "height" : 3, + "secure_url" : "mockurl", + "url" : "mockurl", + "width" : 3 + } + } + }, + "dateTime" : 44354, + "deviceID" : "mockDeviceId2", + "deviceName" : "MockHouseDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "mockActivityId", + "callingUser" : "mockCallingUser5", + "device" : "mockDeviceId2", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "agent" : "mercury", + "keypad" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + }, + "source" : { + "sourceType" : "mercury" + } + }, + { + "action" : "lock", + "callingUser" : { + "FirstName" : "mockFirstName1", + "LastName" : "House", + "UserID" : "mockCallingUser1" + }, + "dateTime" : 543454, + "deviceID" : "mockDevice1", + "deviceName" : "MockHouseGDoor", + "deviceType" : "lock", + "entities" : { + "activity" : "mockActivityId1", + "callingUser" : "mockCallingUser1", + "device" : "mockDevice1", + "house" : "mock-house-id", + "otherUser" : "deleted" + }, + "house" : { + "houseID" : "mock-house-id", + "houseName" : "MockHouse" + }, + "info" : { + "DateLogActionID" : "mockDevice1+Time", + "remote" : true + }, + "otherUser" : { + "FirstName" : "Unknown", + "LastName" : "User", + "PhoneNo" : "deleted", + "UserID" : "deleted", + "UserName" : "deleteduser" + } + } +] diff --git a/tests/test_activity.py b/tests/test_activity.py new file mode 100644 index 0000000..afb6799 --- /dev/null +++ b/tests/test_activity.py @@ -0,0 +1,51 @@ +import os +import unittest + +from august.activity import ( + ACTION_DOOR_CLOSED, + ACTION_DOOR_OPEN, + ACTION_DOORBELL_CALL_HANGUP, + ACTION_DOORBELL_CALL_INITIATED, + ACTION_DOORBELL_CALL_MISSED, + ACTION_DOORBELL_MOTION_DETECTED, + ACTION_LOCK_LOCK, + ACTION_LOCK_ONETOUCHLOCK, + ACTION_LOCK_UNLOCK, + ACTIVITY_ACTION_STATES, + ACTIVITY_ACTIONS_DOOR_OPERATION, + ACTIVITY_ACTIONS_DOORBELL_DING, + ACTIVITY_ACTIONS_DOORBELL_MOTION, + ACTIVITY_ACTIONS_DOORBELL_VIEW, + ACTIVITY_ACTIONS_LOCK_OPERATION, +) +from august.lock import LockDoorStatus, LockStatus + + +class TestActivity(unittest.TestCase): + def test_activity_action_states(self): + self.assertIs( + ACTIVITY_ACTION_STATES[ACTION_LOCK_ONETOUCHLOCK], LockStatus.LOCKED + ) + self.assertIs(ACTIVITY_ACTION_STATES[ACTION_LOCK_LOCK], LockStatus.LOCKED) + self.assertIs(ACTIVITY_ACTION_STATES[ACTION_LOCK_UNLOCK], LockStatus.UNLOCKED) + self.assertIs(ACTIVITY_ACTION_STATES[ACTION_DOOR_CLOSED], LockDoorStatus.CLOSED) + self.assertIs(ACTIVITY_ACTION_STATES[ACTION_DOOR_OPEN], LockDoorStatus.OPEN) + + def test_activity_actions(self): + self.assertCountEqual( + ACTIVITY_ACTIONS_DOORBELL_DING, + [ACTION_DOORBELL_CALL_MISSED, ACTION_DOORBELL_CALL_HANGUP], + ) + self.assertCountEqual( + ACTIVITY_ACTIONS_DOORBELL_MOTION, [ACTION_DOORBELL_MOTION_DETECTED] + ) + self.assertCountEqual( + ACTIVITY_ACTIONS_DOORBELL_VIEW, [ACTION_DOORBELL_CALL_INITIATED] + ) + self.assertCountEqual( + ACTIVITY_ACTIONS_LOCK_OPERATION, + [ACTION_LOCK_ONETOUCHLOCK, ACTION_LOCK_LOCK, ACTION_LOCK_UNLOCK], + ) + self.assertCountEqual( + ACTIVITY_ACTIONS_DOOR_OPERATION, [ACTION_DOOR_OPEN, ACTION_DOOR_CLOSED] + ) diff --git a/tests/test_api.py b/tests/test_api.py index 1a2f7c0..5eb8afb 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -5,37 +5,44 @@ import requests_mock from dateutil.tz import tzutc -from august.api import API_GET_DOORBELLS_URL, Api, API_GET_LOCKS_URL, \ - API_GET_LOCK_STATUS_URL, API_LOCK_URL, API_UNLOCK_URL, API_GET_LOCK_URL, \ - API_GET_DOORBELL_URL, API_GET_PINS_URL -from august.lock import LockStatus, LockDoorStatus +import august.activity +from august.api import ( + API_GET_DOORBELL_URL, + API_GET_DOORBELLS_URL, + API_GET_HOUSE_ACTIVITIES_URL, + API_GET_LOCK_STATUS_URL, + API_GET_LOCK_URL, + API_GET_LOCKS_URL, + API_GET_PINS_URL, + API_LOCK_URL, + API_UNLOCK_URL, + Api, +) +from august.lock import LockDoorStatus, LockStatus ACCESS_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" def load_fixture(filename): """Load a fixture.""" - path = os.path.join(os.path.dirname(__file__), 'fixtures', filename) + path = os.path.join(os.path.dirname(__file__), "fixtures", filename) with open(path) as fptr: return fptr.read() def utc_of(year, month, day, hour, minute, second, microsecond): - return datetime(year, month, day, hour, minute, second, microsecond, - tzinfo=tzutc()) + return datetime(year, month, day, hour, minute, second, microsecond, tzinfo=tzutc()) class TestApi(unittest.TestCase): @requests_mock.Mocker() def test_get_doorbells(self, mock): mock.register_uri( - "get", - API_GET_DOORBELLS_URL, - text=load_fixture("get_doorbells.json")) + "get", API_GET_DOORBELLS_URL, text=load_fixture("get_doorbells.json") + ) api = Api() - doorbells = sorted(api.get_doorbells(ACCESS_TOKEN), - key=lambda d: d.device_id) + doorbells = sorted(api.get_doorbells(ACCESS_TOKEN), key=lambda d: d.device_id) self.assertEqual(2, len(doorbells)) @@ -54,8 +61,7 @@ def test_get_doorbells(self, mock): self.assertEqual("Front Door", second.device_name) self.assertEqual("doorbell_call_status_online", second.status) self.assertEqual(True, second.has_subscription) - self.assertEqual("https://image.com/vmk16naaaa7ibuey7sar.jpg", - second.image_url) + self.assertEqual("https://image.com/vmk16naaaa7ibuey7sar.jpg", second.image_url) self.assertEqual("3dd2accaea08", second.house_id) @requests_mock.Mocker() @@ -63,7 +69,8 @@ def test_get_doorbell_detail(self, mock): mock.register_uri( "get", API_GET_DOORBELL_URL.format(doorbell_id="K98GiDT45GUL"), - text=load_fixture("get_doorbell.json")) + text=load_fixture("get_doorbell.json"), + ) api = Api() doorbell = api.get_doorbell_detail(ACCESS_TOKEN, "K98GiDT45GUL") @@ -76,15 +83,13 @@ def test_get_doorbell_detail(self, mock): self.assertEqual("doorbell_call_status_online", doorbell.status) self.assertEqual(True, doorbell.is_online) self.assertEqual(True, doorbell.has_subscription) - self.assertEqual("https://image.com/vmk16naaaa7ibuey7sar.jpg", - doorbell.image_url) + self.assertEqual( + "https://image.com/vmk16naaaa7ibuey7sar.jpg", doorbell.image_url + ) @requests_mock.Mocker() def test_get_locks(self, mock): - mock.register_uri( - "get", - API_GET_LOCKS_URL, - text=load_fixture("get_locks.json")) + mock.register_uri("get", API_GET_LOCKS_URL, text=load_fixture("get_locks.json")) api = Api() locks = sorted(api.get_locks(ACCESS_TOKEN), key=lambda d: d.device_id) @@ -105,10 +110,7 @@ def test_get_locks(self, mock): @requests_mock.Mocker() def test_get_operable_locks(self, mock): - mock.register_uri( - "get", - API_GET_LOCKS_URL, - text=load_fixture("get_locks.json")) + mock.register_uri("get", API_GET_LOCKS_URL, text=load_fixture("get_locks.json")) api = Api() locks = api.get_operable_locks(ACCESS_TOKEN) @@ -125,13 +127,12 @@ def test_get_operable_locks(self, mock): def test_get_lock_detail(self, mock): mock.register_uri( "get", - API_GET_LOCK_URL.format( - lock_id="A6697750D607098BAE8D6BAA11EF8063"), - text=load_fixture("get_lock.json")) + API_GET_LOCK_URL.format(lock_id="A6697750D607098BAE8D6BAA11EF8063"), + text=load_fixture("get_lock.json"), + ) api = Api() - lock = api.get_lock_detail(ACCESS_TOKEN, - "A6697750D607098BAE8D6BAA11EF8063") + lock = api.get_lock_detail(ACCESS_TOKEN, "A6697750D607098BAE8D6BAA11EF8063") self.assertEqual("A6697750D607098BAE8D6BAA11EF8063", lock.device_id) self.assertEqual("Front Door Lock", lock.device_name) @@ -148,7 +149,8 @@ def test_get_lock_status_with_locked_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"status\": \"kAugLockState_Locked\"}") + text='{"status": "kAugLockState_Locked"}', + ) api = Api() status = api.get_lock_status(ACCESS_TOKEN, lock_id) @@ -161,8 +163,9 @@ def test_get_lock_and_door_status_with_locked_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"status\": \"kAugLockState_Locked\"" - ",\"doorState\": \"kAugLockDoorState_Closed\"}") + text='{"status": "kAugLockState_Locked"' + ',"doorState": "kAugLockDoorState_Closed"}', + ) api = Api() status, door_status = api.get_lock_status(ACCESS_TOKEN, lock_id, True) @@ -176,7 +179,8 @@ def test_get_lock_status_with_unlocked_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"status\": \"kAugLockState_Unlocked\"}") + text='{"status": "kAugLockState_Unlocked"}', + ) api = Api() status = api.get_lock_status(ACCESS_TOKEN, lock_id) @@ -189,7 +193,8 @@ def test_get_lock_status_with_unknown_status_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"status\": \"not_advertising\"}") + text='{"status": "not_advertising"}', + ) api = Api() status = api.get_lock_status(ACCESS_TOKEN, lock_id) @@ -202,7 +207,8 @@ def test_get_lock_door_status_with_closed_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"doorState\": \"kAugLockDoorState_Closed\"}") + text='{"doorState": "kAugLockDoorState_Closed"}', + ) api = Api() door_status = api.get_lock_door_status(ACCESS_TOKEN, lock_id) @@ -215,7 +221,8 @@ def test_get_lock_door_status_with_open_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"doorState\": \"kAugLockDoorState_Open\"}") + text='{"doorState": "kAugLockDoorState_Open"}', + ) api = Api() door_status = api.get_lock_door_status(ACCESS_TOKEN, lock_id) @@ -228,12 +235,12 @@ def test_get_lock_and_door_status_with_open_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"status\": \"kAugLockState_Unlocked\"" - ",\"doorState\": \"kAugLockDoorState_Open\"}") + text='{"status": "kAugLockState_Unlocked"' + ',"doorState": "kAugLockDoorState_Open"}', + ) api = Api() - door_status, status = api.get_lock_door_status(ACCESS_TOKEN, lock_id, - True) + door_status, status = api.get_lock_door_status(ACCESS_TOKEN, lock_id, True) self.assertEqual(LockDoorStatus.OPEN, door_status) self.assertEqual(LockStatus.UNLOCKED, status) @@ -244,7 +251,8 @@ def test_get_lock_door_status_with_unknown_response(self, mock): mock.register_uri( "get", API_GET_LOCK_STATUS_URL.format(lock_id=lock_id), - text="{\"doorState\": \"not_advertising\"}") + text='{"doorState": "not_advertising"}', + ) api = Api() door_status = api.get_lock_door_status(ACCESS_TOKEN, lock_id) @@ -257,10 +265,11 @@ def test_lock(self, mock): mock.register_uri( "put", API_LOCK_URL.format(lock_id=lock_id), - text="{\"status\":\"locked\"," - "\"dateTime\":\"2017-12-10T07:43:39.056Z\"," - "\"isLockStatusChanged\":false," - "\"valid\":true}") + text='{"status":"locked",' + '"dateTime":"2017-12-10T07:43:39.056Z",' + '"isLockStatusChanged":false,' + '"valid":true}', + ) api = Api() status = api.lock(ACCESS_TOKEN, lock_id) @@ -271,9 +280,8 @@ def test_lock(self, mock): def test_unlock(self, mock): lock_id = 1234 mock.register_uri( - "put", - API_UNLOCK_URL.format(lock_id=lock_id), - text="{\"status\": \"unlocked\"}") + "put", API_UNLOCK_URL.format(lock_id=lock_id), text='{"status": "unlocked"}' + ) api = Api() status = api.unlock(ACCESS_TOKEN, lock_id) @@ -286,7 +294,8 @@ def test_get_pins(self, mock): mock.register_uri( "get", API_GET_PINS_URL.format(lock_id=lock_id), - text=load_fixture("get_pins.json")) + text=load_fixture("get_pins.json"), + ) api = Api() pins = api.get_pins(ACCESS_TOKEN, lock_id) @@ -304,15 +313,34 @@ def test_get_pins(self, mock): self.assertEqual("John", first.first_name) self.assertEqual("Doe", first.last_name) self.assertEqual(True, first.unverified) - self.assertEqual(utc_of(2016, 11, 26, 22, 27, 11, 176000), - first.created_at) - self.assertEqual(utc_of(2017, 11, 23, 00, 42, 19, 470000), - first.updated_at) - self.assertEqual(utc_of(2017, 12, 10, 3, 12, 55, 563000), - first.loaded_date) - self.assertEqual(utc_of(2018, 1, 1, 1, 1, 1, 563000), - first.access_start_time) - self.assertEqual(utc_of(2018, 12, 1, 1, 1, 1, 563000), - first.access_end_time) - self.assertEqual(utc_of(2018, 11, 5, 10, 2, 41, 684000), - first.access_times) + self.assertEqual(utc_of(2016, 11, 26, 22, 27, 11, 176000), first.created_at) + self.assertEqual(utc_of(2017, 11, 23, 00, 42, 19, 470000), first.updated_at) + self.assertEqual(utc_of(2017, 12, 10, 3, 12, 55, 563000), first.loaded_date) + self.assertEqual(utc_of(2018, 1, 1, 1, 1, 1, 563000), first.access_start_time) + self.assertEqual(utc_of(2018, 12, 1, 1, 1, 1, 563000), first.access_end_time) + self.assertEqual(utc_of(2018, 11, 5, 10, 2, 41, 684000), first.access_times) + + @requests_mock.Mocker() + def test_get_house_activities(self, mock): + house_id = 1234 + mock.register_uri( + "get", + API_GET_HOUSE_ACTIVITIES_URL.format(house_id=house_id), + text=load_fixture("get_house_activities.json"), + ) + + api = Api() + activities = api.get_house_activities(ACCESS_TOKEN, house_id) + + self.assertEqual(10, len(activities)) + + self.assertIsInstance(activities[0], august.activity.LockOperationActivity) + self.assertIsInstance(activities[1], august.activity.LockOperationActivity) + self.assertIsInstance(activities[2], august.activity.LockOperationActivity) + self.assertIsInstance(activities[3], august.activity.LockOperationActivity) + self.assertIsInstance(activities[4], august.activity.LockOperationActivity) + self.assertIsInstance(activities[5], august.activity.DoorOperationActivity) + self.assertIsInstance(activities[6], august.activity.DoorOperationActivity) + self.assertIsInstance(activities[7], august.activity.DoorOperationActivity) + self.assertIsInstance(activities[8], august.activity.LockOperationActivity) + self.assertIsInstance(activities[9], august.activity.LockOperationActivity) diff --git a/tests/test_authenticator.py b/tests/test_authenticator.py index c43948f..fa6c78f 100644 --- a/tests/test_authenticator.py +++ b/tests/test_authenticator.py @@ -1,8 +1,8 @@ import unittest -from datetime import datetime, timezone, timedelta -from dateutil.tz import tzutc +from datetime import datetime, timedelta, timezone from unittest.mock import Mock, patch +from dateutil.tz import tzutc from requests import RequestException from august.authenticator import (AuthenticationState, Authenticator,