Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions nuki_bridge/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
from scan_ble import find_ble_device
from utils import logger, handler
from web_server import WebServer
from nuki_manager import NukiManager

logging.getLogger("aiohttp").addHandler(handler)
logging.getLogger("aiohttp").setLevel(logging.ERROR)
logging.getLogger("bleak").addHandler(handler)
logging.getLogger("bleak").setLevel(logging.ERROR)
logging.getLogger("pyNukiBT").addHandler(handler)
logging.getLogger("pyNukiBT").setLevel(logging.INFO)
logging.getLogger("pyNukiBT").setLevel(logging.WARNING)


def _add_devices_to_manager(data, nuki_manager):
def _add_devices_to_manager(data, nuki_manager:NukiManager):
for ls in data["smartlock"]:
address = ls["address"]
auth_id = bytes.fromhex(ls["auth_id"])
Expand All @@ -42,14 +43,17 @@ def _add_devices_to_manager(data, nuki_manager):

if not args.verbose:
logger.setLevel(level=logging.INFO)
logging.getLogger("pyNukiBT").setLevel(logging.WARNING)
logging.getLogger("aiohttp").setLevel(level=logging.ERROR)
logging.getLogger("bleak").setLevel(level=logging.ERROR)
elif args.verbose == 1:
logger.setLevel(level=logging.DEBUG)
logging.getLogger("pyNukiBT").setLevel(logging.INFO)
logging.getLogger("aiohttp").setLevel(level=logging.INFO)
logging.getLogger("bleak").setLevel(level=logging.INFO)
elif args.verbose == 2:
logger.setLevel(level=logging.DEBUG)
logging.getLogger("pyNukiBT").setLevel(logging.DEBUG)
logging.getLogger("aiohttp").setLevel(level=logging.DEBUG)
logging.getLogger("bleak").setLevel(level=logging.DEBUG)

Expand All @@ -75,16 +79,10 @@ def _add_devices_to_manager(data, nuki_manager):

bridge_public_key, bridge_private_key = _generate_bridge_keys()
nuki = NukiDevice(address, None, None, bridge_public_key, bridge_private_key, nuki_manager.app_id, nuki_manager.name, nuki_manager.type_id)
ret = nuki.pair()
logger.info(f"Pairing completed, nuki_public_key: {ret['nuki_public_key'].hex()}")
logger.info(f"Pairing completed, auth_id: {ret['auth_id'].hex()}")
nuki_manager.add_nuki(nuki)

loop = asyncio.get_event_loop()

def pairing_completed(paired_nuki):
logger.info(f"Pairing completed, nuki_public_key: {paired_nuki.nuki_public_key.hex()}")
logger.info(f"Pairing completed, auth_id: {paired_nuki.auth_id.hex()}")
loop.stop()
loop.create_task(nuki.pair(pairing_completed))
loop.run_forever()
else:
if not nuki_manager.device_list:
_add_devices_to_manager(data, nuki_manager)
Expand Down
43 changes: 17 additions & 26 deletions nuki_bridge/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,33 +101,24 @@ def init_config(config_file, addon_config_file):

# Pair
nuki = NukiDevice(address, None, None, bridge_public_key, bridge_private_key, nuki_manager.app_id, nuki_manager.name, nuki_manager.type_id)
nuki_manager.add_nuki(nuki)

loop = asyncio.new_event_loop()

nuki_manager.start(loop)

def pairing_completed(paired_nuki):
nuki_public_key = paired_nuki.nuki_public_key.hex()
auth_id = paired_nuki.auth_id.hex()
logger.info(f"Pairing completed, auth_id: {auth_id}")
logger.info(f"nuki_public_key: {nuki_public_key}")
logger.info(f"********************************************************************")
logger.info(f"* *")
logger.info(f"* Pairing completed! *")
logger.info(f"* Access Token *")
logger.info(f"* {token} *")
logger.info(f"* *")
logger.info(f"********************************************************************")
smartlock['nuki_public_key'] = nuki_public_key
smartlock['auth_id'] = auth_id

data['smartlock'] = [smartlock]
yaml.dump(data, open(config_file, 'w'))
loop.stop()

loop.create_task(nuki.pair(pairing_completed))
loop.run_forever()
ret = nuki.pair()
nuki_public_key = ret["nuki_public_key"].hex()
auth_id = ret["auth_id"].hex()
logger.info(f"Pairing completed, auth_id: {auth_id}")
logger.info(f"nuki_public_key: {nuki_public_key}")
logger.info(f"********************************************************************")
logger.info(f"* *")
logger.info(f"* Pairing completed! *")
logger.info(f"* Access Token *")
logger.info(f"* {token} *")
logger.info(f"* *")
logger.info(f"********************************************************************")
smartlock['nuki_public_key'] = nuki_public_key
smartlock['auth_id'] = auth_id

data['smartlock'] = [smartlock]
yaml.dump(data, open(config_file, 'w'))

return nuki_manager, data

Expand Down
7 changes: 5 additions & 2 deletions nuki_bridge/nuki_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ def nuki_by_id(self, nuki_id) -> NukiDevice:
return next(nuki for nuki in self._devices.values() if nuki.config.get("nuki_id") == nuki_id)

def add_nuki(self, nuki: NukiDevice):
self._devices[nuki.address] = nuki
self._devices[nuki._address] = nuki
def _cb():
self.nuki_newstate(nuki)
nuki.subscribe(_cb)

@property
def device_list(self):
Expand Down Expand Up @@ -84,6 +87,6 @@ async def stop_scanning(self, timeout=10.0):
async def _detected_ibeacon(self, device: BLEDevice, advertisement_data: AdvertisementData):
if device.address in self._devices:
nuki = self._devices[device.address]
await nuki.parse_advertisement_data(device, advertisement_data)
nuki.parse_advertisement_data(device, advertisement_data)
if nuki.poll_needed():
await nuki.update_state()
2 changes: 1 addition & 1 deletion nuki_bridge/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
aiohttp==3.8.1
bleak==0.20.1
PyYAML==6.0
pyNukiBT @ git+https://github.com/ronengr/pyNukiBT.git@main
pyNukiBT==0.0.4
15 changes: 9 additions & 6 deletions nuki_bridge/web_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def start(self):
web.get('/callback/add', self.callback_add),
web.get('/callback/list', self.callback_list),
web.get('/callback/remove', self.callback_remove),
web.get('/verify_pin', self.verify_pin),
web.get('/request_last_log_entry', self.request_last_log_entry),
web.get('/verify_security_pin', self.verify_security_pin),
web.get('/request_log_entries', self.request_log_entries),
])
app.on_startup.append(self._startup)
web.run_app(app, host=self._host, port=self._port, loop=self._loop)
Expand Down Expand Up @@ -172,24 +172,27 @@ async def nuki_lock(self, request):
res = json.dumps({"success": True, "batteryCritical": n.is_battery_critical})
return web.Response(text=res)

async def verify_pin(self, request):
async def verify_security_pin(self, request):
if not self._check_token(request):
raise web.HTTPForbidden()
n: NukiDevice = self.nuki_manager.nuki_by_id(int(request.query["nukiId"], base=16))
try:
ret = await n.verify_pin(int(request.query["pin"], base=10))
ret = await n.verify_security_pin(int(request.query["pin"], base=10))
except NukiErrorException as ex:
res = json.dumps({"success" : False, "error_code": ex.error_code})
else:
res = json.dumps({"success": ret})
return web.Response(text=res)

async def request_last_log_entry(self, request):
async def request_log_entries(self, request):
if not self._check_token(request):
raise web.HTTPForbidden()
n: NukiDevice = self.nuki_manager.nuki_by_id(int(request.query["nukiId"], base=16))
security_pin=int(request.query.get("security_pin"), base=10)
count=int(request.query.get("count", default=1))
start_index=int(request.query.get("start_index", default=0))
try:
ret = await n.request_last_log_entry(int(request.query["pin"], base=10))
ret = await n.request_log_entries(security_pin=security_pin, count=count, start_index=start_index)
except NukiErrorException as ex:
res = json.dumps({"success" : False, "error_code": ex.error_code})
else:
Expand Down