Skip to content

Commit

Permalink
Merge pull request #33 from bdraco/bridge_and_doorsense
Browse files Browse the repository at this point in the history
Expose bridge information and if doorsense is installed
  • Loading branch information
snjoetw authored Feb 13, 2020
2 parents d8dfd2e + 203a0ad commit d7e1756
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 15 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ august/__init__.py
august/activity.py
august/api.py
august/authenticator.py
august/bridge.py
august/device.py
august/doorbell.py
august/keypad.py
Expand Down
56 changes: 56 additions & 0 deletions august/bridge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from enum import Enum

from august.device import DeviceDetail


class BridgeStatus(Enum):
ONLINE = "online"
UNKNOWN = "unknown"


class BridgeDetail(DeviceDetail):
def __init__(self, house_id, data):
super().__init__(data["_id"], None, house_id, None, data["firmwareVersion"])

self._operative = data["operative"]

if "status" in data:
self._status = BridgeStatusDetail(data["status"])
else:
self._status = None

@property
def status(self):
return self._status

@property
def operative(self):
return self._operative


class BridgeStatusDetail:
def __init__(self, data):
self._current = BridgeStatus.UNKNOWN

if "current" in data and data["current"] == "online":
self._current = BridgeStatus.ONLINE

self._updated = data["updated"] if "updated" in data else None
self._last_online = data["lastOnline"] if "lastOnline" in data else None
self._last_offline = data["lastOffline"] if "lastOffline" in data else None

@property
def current(self):
return self._current

@property
def updated(self):
return self._updated

@property
def last_online(self):
return self._last_online

@property
def last_offline(self):
return self._last_offline
35 changes: 26 additions & 9 deletions august/lock.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from enum import Enum

from august.bridge import BridgeDetail
from august.device import Device, DeviceDetail
from august.keypad import KeypadDetail


class Lock(Device):
def __init__(self, device_id, data):
super().__init__(
device_id,
data["LockName"],
data["HouseID"],
device_id, data["LockName"], data["HouseID"],
)
self._user_type = data["UserType"]

Expand All @@ -19,9 +18,8 @@ def is_operable(self):

def __repr__(self):
return "Lock(id={}, name={}, house_id={})".format(
self.device_id,
self.device_name,
self.house_id)
self.device_id, self.device_name, self.house_id
)


class LockDetail(DeviceDetail):
Expand All @@ -31,10 +29,21 @@ def __init__(self, data):
data["LockName"],
data["HouseID"],
data["SerialNumber"],
data["currentFirmwareVersion"])
data["currentFirmwareVersion"],
)

if 'keypad' in data:
self._keypad_detail = KeypadDetail(self.house_id, data['keypad'])
if "Bridge" in data:
self._bridge = BridgeDetail(self.house_id, data["Bridge"])
else:
self._bridge = None

self._doorsense = False
if "LockStatus" in data:
if "doorState" in data["LockStatus"]:
self._doorsense = True

if "keypad" in data:
self._keypad_detail = KeypadDetail(self.house_id, data["keypad"])
else:
self._keypad_detail = None

Expand All @@ -48,6 +57,14 @@ def battery_level(self):
def keypad(self):
return self._keypad_detail

@property
def bridge(self):
return self._bridge

@property
def doorsense(self):
return self._doorsense


class LockStatus(Enum):
LOCKED = "locked"
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='py-august',
version='0.12.0',
version='0.13.0',
packages=['august'],
url='https://github.com/snjoetw/py-august',
license='MIT',
Expand Down
68 changes: 68 additions & 0 deletions tests/fixtures/get_lock.offline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"Calibrated" : false,
"Created" : "2000-00-00T00:00:00.447Z",
"HouseID" : "houseid",
"HouseName" : "MockName",
"LockID" : "ABC",
"LockName" : "Test",
"LockStatus" : {
"status" : "unknown"
},
"OfflineKeys" : {
"created" : [],
"createdhk" : [
{
"UserID" : "mock-user-id",
"created" : "2000-00-00T00:00:00.447Z",
"key" : "mockkey",
"slot" : 12
}
],
"deleted" : [],
"loaded" : [
{
"UserID" : "userid",
"created" : "2000-00-00T00:00:00.447Z",
"key" : "key",
"loaded" : "2000-00-00T00:00:00.447Z",
"slot" : 1
}
]
},
"SerialNumber" : "ABC",
"Type" : 3,
"Updated" : "2000-00-00T00:00:00.447Z",
"battery" : -1,
"cameras" : [],
"currentFirmwareVersion" : "undefined-1.59.0-1.13.2",
"geofenceLimits" : {
"ios" : {
"debounceInterval" : 90,
"gpsAccuracyMultiplier" : 2.5,
"maximumGeofence" : 5000,
"minGPSAccuracyRequired" : 80,
"minimumGeofence" : 100
}
},
"homeKitEnabled" : false,
"isGalileo" : false,
"macAddress" : "a:b:c",
"parametersToSet" : {},
"pubsubChannel" : "mockpubsub",
"ruleHash" : {},
"skuNumber" : "AUG-X",
"supportsEntryCodes" : false,
"users" : {
"mockuserid" : {
"FirstName" : "MockName",
"LastName" : "House",
"UserType" : "superuser",
"identifiers" : [
"phone:+15558675309",
"email:mockme@mock.org"
]
}
},
"zWaveDSK" : "1-2-3-4",
"zWaveEnabled" : true
}
File renamed without changes.
51 changes: 51 additions & 0 deletions tests/fixtures/get_lock.online_with_doorsense.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"Bridge" : {
"_id" : "bridgeid",
"deviceModel" : "august-connect",
"firmwareVersion" : "2.2.1",
"hyperBridge" : true,
"mfgBridgeID" : "C5WY200WSH",
"operative" : true,
"status" : {
"current" : "online",
"lastOffline" : "2000-00-00T00:00:00.447Z",
"lastOnline" : "2000-00-00T00:00:00.447Z",
"updated" : "2000-00-00T00:00:00.447Z"
}
},
"Calibrated" : false,
"Created" : "2000-00-00T00:00:00.447Z",
"HouseID" : "123",
"HouseName" : "Test",
"LockID" : "ABC",
"LockName" : "Online door with doorsense",
"LockStatus" : {
"dateTime" : "2000-00-00T00:00:00.447Z",
"doorState" : "open",
"isLockStatusChanged" : false,
"status" : "locked",
"valid" : true
},
"SerialNumber" : "XY",
"Type" : 1001,
"Updated" : "2000-00-00T00:00:00.447Z",
"battery" : 0.922,
"currentFirmwareVersion" : "undefined-4.3.0-1.8.14",
"homeKitEnabled" : true,
"hostLockInfo" : {
"manufacturer" : "yale",
"productID" : 1536,
"productTypeID" : 32770,
"serialNumber" : "ABC"
},
"isGalileo" : false,
"macAddress" : "12:22",
"pins" : {
"created" : [],
"loaded" : []
},
"skuNumber" : "AUG-MD01",
"supportsEntryCodes" : true,
"timeZone" : "Pacific/Hawaii",
"zWaveEnabled" : false
}
58 changes: 53 additions & 5 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
import unittest
from datetime import datetime

import requests_mock
from dateutil.tz import tzutc

import august.activity
import requests_mock
from august.api import (
API_GET_DOORBELL_URL,
API_GET_DOORBELLS_URL,
Expand All @@ -18,7 +16,9 @@
API_UNLOCK_URL,
Api,
)
from august.bridge import BridgeDetail, BridgeStatus, BridgeStatusDetail
from august.lock import LockDoorStatus, LockStatus
from dateutil.tz import tzutc

ACCESS_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"

Expand Down Expand Up @@ -125,11 +125,35 @@ def test_get_operable_locks(self, mock):
self.assertEqual(True, first.is_operable)

@requests_mock.Mocker()
def test_get_lock_detail(self, mock):
def test_get_lock_detail_with_doorsense_bridge_online(self, mock):
mock.register_uri(
"get",
API_GET_LOCK_URL.format(lock_id="ABC"),
text=load_fixture("get_lock.online_with_doorsense.json"),
)

api = Api()
lock = api.get_lock_detail(ACCESS_TOKEN, "ABC")

self.assertEqual("ABC", lock.device_id)
self.assertEqual("Online door with doorsense", lock.device_name)
self.assertEqual("123", lock.house_id)
self.assertEqual("XY", lock.serial_number)
self.assertEqual("undefined-4.3.0-1.8.14", lock.firmware_version)
self.assertEqual(92, lock.battery_level)
self.assertEqual(None, lock.keypad)
self.assertIsInstance(lock.bridge, BridgeDetail)
self.assertIsInstance(lock.bridge.status, BridgeStatusDetail)
self.assertEqual(BridgeStatus.ONLINE, lock.bridge.status.current)
self.assertEqual(True, lock.bridge.operative)
self.assertEqual(True, lock.doorsense)

@requests_mock.Mocker()
def test_get_lock_detail_bridge_online(self, mock):
mock.register_uri(
"get",
API_GET_LOCK_URL.format(lock_id="A6697750D607098BAE8D6BAA11EF8063"),
text=load_fixture("get_lock.json"),
text=load_fixture("get_lock.online.json"),
)

api = Api()
Expand All @@ -143,6 +167,30 @@ def test_get_lock_detail(self, mock):
self.assertEqual(88, lock.battery_level)
self.assertEqual("Medium", lock.keypad.battery_level)
self.assertEqual("5bc65c24e6ef2a263e1450a8", lock.keypad.device_id)
self.assertIsInstance(lock.bridge, BridgeDetail)
self.assertEqual(True, lock.bridge.operative)
self.assertEqual(True, lock.doorsense)

@requests_mock.Mocker()
def test_get_lock_detail_bridge_offline(self, mock):
mock.register_uri(
"get",
API_GET_LOCK_URL.format(lock_id="ABC"),
text=load_fixture("get_lock.offline.json"),
)

api = Api()
lock = api.get_lock_detail(ACCESS_TOKEN, "ABC")

self.assertEqual("ABC", lock.device_id)
self.assertEqual("Test", lock.device_name)
self.assertEqual("houseid", lock.house_id)
self.assertEqual("ABC", lock.serial_number)
self.assertEqual("undefined-1.59.0-1.13.2", lock.firmware_version)
self.assertEqual(-100, lock.battery_level)
self.assertEqual(None, lock.keypad)
self.assertEqual(None, lock.bridge)
self.assertEqual(False, lock.doorsense)

@requests_mock.Mocker()
def test_get_lock_status_with_locked_response(self, mock):
Expand Down

0 comments on commit d7e1756

Please sign in to comment.