blob: b5cfa62555dd324fc4feba15b56382237d2a0984 [file] [log] [blame]
#
# Copyright (c) 2021-2022 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import ctypes
from enum import Enum
from typing import Optional
from chip.configuration import GetCommissionerCAT, GetLocalNodeId
from chip.internal.types import NetworkCredentialsRequested, OperationalCredentialsRequested, PairingComplete
from chip.native import GetLibraryHandle, NativeLibraryHandleMethodArguments
# Not using c_void_p directly is IMPORTANT. Python auto-casts c_void_p
# to intergers and this can cause 32/64 bit issues.
class Commissioner_p(ctypes.c_void_p):
pass
class ThreadBlob_p(ctypes.c_void_p):
pass
@NetworkCredentialsRequested
def OnNetworkCredentialsRequested():
GetCommissioner()._OnNetworkCredentialsRequested()
@OperationalCredentialsRequested
def OnOperationalCredentialsRequested(csr, csr_length):
GetCommissioner()._OnOperationalCredentialsRequested(
ctypes.string_at(csr, csr_length))
@PairingComplete
def OnPairingComplete(err: int):
GetCommissioner()._OnPairingComplete(err)
class PairingState(Enum):
"""States throughout a pairing flow.
Devices generally go through:
initialized -> pairing -> netcreds -> opcreds -> done (initialized)
where network credentials may be skipped if device is already on the network.
"""
INITIALIZED = 0
PAIRING = 1
NEEDS_NETCREDS = 2
NEEDS_OPCREDS = 3
class Commissioner:
"""Commissioner wraps the DeviceCommissioner native class.
The commissioner is a DeviceController that supports pairing. Since the device
controller supports multiple devices, this class is expected to be used
as a singleton
"""
def __init__(self, handle: ctypes.CDLL, native: Commissioner_p):
self._handle = handle
self._native = native
self.pairing_state = PairingState.INITIALIZED
self.on_pairing_complete = None
def BlePair(self, remoteDeviceId: int, pinCode: int, discriminator: int):
result = self._handle.pychip_internal_Commissioner_BleConnectForPairing(
self._native, remoteDeviceId, pinCode, discriminator)
if result != 0:
raise Exception("Failed to pair. CHIP Error code %d" % result)
self.pairing_state = PairingState.PAIRING
def Unpair(self, remoteDeviceId: int):
result = self._handle.pychip_internal_Commissioner_Unpair(
self._native, remoteDeviceId)
if result != 0:
raise Exception("Failed to unpair. CHIP Error code %d" % result)
def _OnPairingComplete(self, err: int):
self.pairing_state = PairingState.INITIALIZED
if self.on_pairing_complete:
self.on_pairing_complete(err)
def _SetNativeCallSignatues(handle: ctypes.CDLL):
"""Sets up the FFI types for the cdll handle."""
setter = NativeLibraryHandleMethodArguments(handle)
setter.Set('pychip_internal_Commissioner_New',
Commissioner_p, [ctypes.c_uint64, ctypes.c_uint32])
setter.Set('pychip_internal_Commissioner_Unpair',
ctypes.c_uint32, [Commissioner_p, ctypes.c_uint64])
setter.Set('pychip_internal_Commissioner_BleConnectForPairing',
ctypes.c_uint32, [Commissioner_p, ctypes.c_uint64, ctypes.c_uint32, cctypes._uint16])
setter.Set('pychip_internal_PairingDelegate_SetPairingCompleteCallback', None, [
PairingComplete])
commissionerSingleton: Optional[Commissioner] = None
def GetCommissioner() -> Commissioner:
"""Gets a reference to the global commissioner singleton.
Uses the configuration GetLocalNodeId() and GetCommissionerCAT().
"""
global commissionerSingleton
if commissionerSingleton is None:
handle = GetLibraryHandle()
_SetNativeCallSignatues(handle)
native = handle.pychip_internal_Commissioner_New(
GetLocalNodeId(), GetCommissionerCAT())
if not native:
raise Exception('Failed to create commissioner object.')
handle.pychip_internal_PairingDelegate_SetPairingCompleteCallback(
OnPairingComplete)
commissionerSingleton = Commissioner(handle, native)
return commissionerSingleton