Back to Connectedhomeip

Multi Fabric - Commissioning and Interactions

docs/development_controllers/matter-repl/Matter_Multi_Fabric_Commissioning.ipynb

1.5.1.06.5 KB
Original Source

Multi Fabric - Commissioning and Interactions

<a href="http://35.236.121.59/hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2Fproject-chip%2Fconnectedhomeip&urlpath=lab%2Ftree%2Fconnectedhomeip%2Fdocs%2Fguides%2Frepl%2FMatter%2520-%2520Multi%2520Fabric%2520Commissioning.ipynb&branch=master"> </a> </br>

This walks through creating multiple controllers on multiple fabrics, using those controllers to commission a target onto those fabrics and finally, interacting with them using the interaction model.

CertificateAuthority, FabricAdmins and Controllers

The CertificateAuthorityManager class manages a set of CertificateAuthority instances (both present in matter.CertificateAuthority. package). a CertificateAuthorityrepresents an operational root of trust, a Root Certificate Authority (CA) with a root key pair with the associated public key (i.e "Root PK"). TheCertificateAuthorityclass manages a list ofFabricAdmins` adminstering a fabric within that CA.

The FabricAdmin class (present in the matter.FabricAdmin package) is responsible for administering a fabric. It houses the Fabric ID and is managed by a CertificateAuthority.

The FabricAdmin can be used to vend ChipDeviceController objects that represent a controller instance with a specific identity grounded in the admin's fabric. This controller can then be used to commission and interact with devices.

Clear Persisted Storage

Let's clear out our persisted storage (if one exists) to start from a clean slate.

python
import os, subprocess

if os.path.isfile('/tmp/repl-storage.json'):
    os.remove('/tmp/repl-storage.json')

# So that the all-clusters-app won't boot with stale prior state.    
os.system('rm -rf /tmp/chip_*')

Initialization

Let's first begin setting up by importing some key modules that are needed to make it easier for us to interact with the Matter stack.

ReplStartup.py is run within the global namespace. This results in all of its imports being made available here.

NOTE: This is not needed if you launch the REPL from the command-line.

python
%reset -f
import importlib.util
spec = importlib.util.find_spec('matter.ReplStartup')
%run {spec.origin} --debug

At startup, the certificateAuthorityManager within REPL will attempt to find CertificateAuthority instances present in persistent storage.If it can't find any (as is the case here), it will create a new CertificateAuthority instance at CA index 0. This CertificateAuthority instance will construct a default FabricAdmin object on FabricAdmin index 0 with a Fabric ID = 1.

python
inspect(caList[0].adminList[0])

The Newly created FabricAdmin will automatically construct a device controller (devCtrl) on it's own fabric.

python
inspect(devCtrl)

Commission onto Fabric 1

Launch Server

Let's launch an instance of the chip-all-clusters-app.

python
import time, os
import subprocess
os.system('pkill -f chip-all-clusters-app')
time.sleep(1)

appPath = '../../../out/linux-x64-all-clusters/chip-all-clusters-app'
process = subprocess.Popen(appPath, stdout=subprocess.DEVNULL)
time.sleep(1)

Commission Target

Commission the target onto Fabric 1 using the default device controller instance with a NodeId of 2.

python
await devCtrl.CommissionOnNetwork(2, 20202021)

Read OpCreds Cluster

Read out the OpCreds cluster to confirm membership into Fabric 1.

python
await devCtrl.ReadAttribute(2, [(Clusters.OperationalCredentials.Attributes.Fabrics)], fabricFiltered=False)

Commission onto Fabric 2

Create a new CertificateAuthority and a new FabricAdmin

We create a new CertificateAuthority instance, and then create a new FabricAdmin that administers Fabric 2 within that CA.

python
certificateAuthority = certificateAuthorityManager.NewCertificateAuthority()

fabricAdmin2 = certificateAuthority.NewFabricAdmin(vendorId=0xFFF1, fabricId=2)

Two different CertificateAuthority instances are now present

python
caList

Here's a brief peek at the JSON data that is in the persisted storage file.

Create a new ChipDeviceController on Fabric 2

python
devCtrl2 = fabricAdmin2.NewController()

Open Commissioning Window

The Controller of Fabric 1 must open the commissioning window that allows the Commissioner of Fabric 2 to join the node to its fabric.

python
await devCtrl.SendCommand(2, 0, Clusters.AdministratorCommissioning.Commands.OpenBasicCommissioningWindow(180),  timedRequestTimeoutMs=10000)
python
await devCtrl2.CommissionOnNetwork(2, 20202021)

Read OpCreds Cluster

Read out the OpCreds cluster to confirm membership into Fabric 2.

python
await devCtrl2.ReadAttribute(2, [(Clusters.OperationalCredentials.Attributes.Fabrics)], fabricFiltered=False)

Relaunch REPL

Let's simulate re-launching the REPL to show-case the capabilities of the persistence storage and its mechanics.

python
%reset -f
import importlib.util
spec = importlib.util.find_spec('matter.ReplStartup')
%run {spec.origin}

The REPL now loaded (through the certificateAuthorityManager) the two certificateAuthority instances that were created in the previous session into the CaList. It has also created a default controller on the first fabric in that list (Fabric 1) as devCtrl.

python
caList

Establish CASE and Read OpCreds

To prove that we do indeed have two distinct fabrics and controllers on each fabric, let's go ahead and update the label of each fabric. To do so, you'd need to successfully establish a CASE session through a controller on the respective fabric, and call the 'UpdateLabel' command.

Underneath the covers, each device controller will do operational discovery of the NodeId being read and establish a CASE session before issuing the IM interaction.

python
devCtrl
python
await devCtrl.SendCommand(2, 0, Clusters.OperationalCredentials.Commands.UpdateFabricLabel("Fabric1Label"))
await devCtrl.ReadAttribute(2, [(Clusters.OperationalCredentials.Attributes.Fabrics)], fabricFiltered=False)

Instantiate a controller on fabric 2 and use it to read out the op creds from that fabric.

python
fabricAdmin2 = caList[1].adminList[0]
devCtrl2 = fabricAdmin2.NewController()

await devCtrl2.SendCommand(2, 0, Clusters.OperationalCredentials.Commands.UpdateFabricLabel("Fabric2Label"))
await devCtrl2.ReadAttribute(2, [(Clusters.OperationalCredentials.Attributes.Fabrics)], fabricFiltered=False)
python
devCtrl2.Shutdown()