Skip to content

Commit

Permalink
[python] Add script interface for node discovery in REPL
Browse files Browse the repository at this point in the history
  • Loading branch information
erjiaqing committed Aug 19, 2022
1 parent 18247f4 commit 0460bba
Show file tree
Hide file tree
Showing 11 changed files with 4,726 additions and 253 deletions.

Large diffs are not rendered by default.

298 changes: 134 additions & 164 deletions docs/guides/repl/Matter - Basic Interactions.ipynb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ shared_library("ChipDeviceCtrl") {
if (chip_controller) {
sources += [
"ChipCommissionableNodeController-ScriptBinding.cpp",
"ChipDeviceController-Discovery.cpp",
"ChipDeviceController-IssueNocChain.cpp",
"ChipDeviceController-ScriptBinding.cpp",
"ChipDeviceController-ScriptDevicePairingDelegate.cpp",
Expand Down Expand Up @@ -109,6 +110,7 @@ shared_library("ChipDeviceCtrl") {
public_deps += [
"${chip_root}/src/controller/data_model",
"${chip_root}/src/credentials:file_attestation_trust_store",
"${chip_root}/third_party/jsoncpp",
]
} else {
public_deps += [ "$chip_data_model" ]
Expand Down
218 changes: 218 additions & 0 deletions src/controller/python/ChipDeviceController-Discovery.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* 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.
*/

/**
* @file
* Implementation of the native methods expected by the Python
* version of Chip Device Manager.
*
*/

#include <controller/CHIPDeviceController.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPTLV.h>
#include <lib/dnssd/Resolver.h>

using namespace chip;

typedef void (*IterateDiscoveredCommissionableNodesFunct)(const char * deviceInfoJson, size_t deviceInfoLen);

extern "C" {

bool pychip_DeviceController_HasDiscoveredCommissionableNode(Controller::DeviceCommissioner * devCtrl)
{
for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
{
const Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
if (dnsSdInfo == nullptr)
{
continue;
}
return true;
}
return false;
}

ChipError::StorageType pychip_DeviceController_DiscoverCommissionableNodes(Controller::DeviceCommissioner * devCtrl,
const uint8_t filterType, const char * filterParam)
{
Dnssd::DiscoveryFilter filter(static_cast<Dnssd::DiscoveryFilterType>(filterType));
switch (static_cast<Dnssd::DiscoveryFilterType>(filterType))
{
case Dnssd::DiscoveryFilterType::kNone:
break;
case Dnssd::DiscoveryFilterType::kShortDiscriminator:
case Dnssd::DiscoveryFilterType::kLongDiscriminator:
case Dnssd::DiscoveryFilterType::kCompressedFabricId:
case Dnssd::DiscoveryFilterType::kVendorId:
case Dnssd::DiscoveryFilterType::kDeviceType: {
// For any numerical filter, convert the string to a filter value
errno = 0;
unsigned long long int numericalArg = strtoull(filterParam, nullptr, 0);
if ((numericalArg == ULLONG_MAX) && (errno == ERANGE))
{
return CHIP_ERROR_INVALID_ARGUMENT.AsInteger();
}
filter.code = static_cast<uint64_t>(numericalArg);
break;
}
case Dnssd::DiscoveryFilterType::kCommissioningMode:
break;
case Dnssd::DiscoveryFilterType::kCommissioner:
filter.code = 1;
break;
case Dnssd::DiscoveryFilterType::kInstanceName:
filter.code = 0;
filter.instanceName = filterParam;
break;
default:
return CHIP_ERROR_INVALID_ARGUMENT.AsInteger();
}

return devCtrl->DiscoverCommissionableNodes(filter).AsInteger();
}

void pychip_DeviceController_IterateDiscoveredCommissionableNodes(Controller::DeviceCommissioner * devCtrl,
IterateDiscoveredCommissionableNodesFunct cb)
{
VerifyOrReturn(cb != nullptr);

for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
{
const Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
if (dnsSdInfo == nullptr)
{
continue;
}

Json::Value jsonVal;

char rotatingId[Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
Encoding::BytesToUppercaseHexString(dnsSdInfo->commissionData.rotatingId, dnsSdInfo->commissionData.rotatingIdLen,
rotatingId, sizeof(rotatingId));

ChipLogProgress(Discovery, "Commissionable Node %d", i);
jsonVal["instanceName"] = dnsSdInfo->commissionData.instanceName;
jsonVal["hostName"] = dnsSdInfo->resolutionData.hostName;
jsonVal["port"] = dnsSdInfo->resolutionData.port;
jsonVal["longDiscriminator"] = dnsSdInfo->commissionData.longDiscriminator;
jsonVal["vendorId"] = dnsSdInfo->commissionData.vendorId;
jsonVal["productId"] = dnsSdInfo->commissionData.productId;
jsonVal["commissioningMode"] = dnsSdInfo->commissionData.commissioningMode;
jsonVal["deviceType"] = dnsSdInfo->commissionData.deviceType;
jsonVal["deviceName"] = dnsSdInfo->commissionData.deviceName;
jsonVal["pairingInstruction"] = dnsSdInfo->commissionData.pairingInstruction;
jsonVal["pairingHint"] = dnsSdInfo->commissionData.pairingHint;
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().HasValue())
{
jsonVal["mrpRetryIntervalIdle"] = dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().Value().count();
}
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().HasValue())
{
jsonVal["mrpRetryIntervalActive"] = dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().Value().count();
}
jsonVal["supportsTcp"] = dnsSdInfo->resolutionData.supportsTcp;
{
Json::Value addresses;
for (unsigned j = 0; j < dnsSdInfo->resolutionData.numIPs; ++j)
{
char buf[Inet::IPAddress::kMaxStringLength];
dnsSdInfo->resolutionData.ipAddress[j].ToString(buf);
addresses[j] = buf;
}
jsonVal["addresses"] = addresses;
}

{
auto str = jsonVal.toStyledString();
cb(str.c_str(), str.size());
}
}
}

void pychip_DeviceController_PrintDiscoveredDevices(Controller::DeviceCommissioner * devCtrl)
{
for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
{
const Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
if (dnsSdInfo == nullptr)
{
continue;
}
char rotatingId[Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
Encoding::BytesToUppercaseHexString(dnsSdInfo->commissionData.rotatingId, dnsSdInfo->commissionData.rotatingIdLen,
rotatingId, sizeof(rotatingId));

ChipLogProgress(Discovery, "Commissionable Node %d", i);
ChipLogProgress(Discovery, "\tInstance name:\t\t%s", dnsSdInfo->commissionData.instanceName);
ChipLogProgress(Discovery, "\tHost name:\t\t%s", dnsSdInfo->resolutionData.hostName);
ChipLogProgress(Discovery, "\tPort:\t\t\t%u", dnsSdInfo->resolutionData.port);
ChipLogProgress(Discovery, "\tLong discriminator:\t%u", dnsSdInfo->commissionData.longDiscriminator);
ChipLogProgress(Discovery, "\tVendor ID:\t\t%u", dnsSdInfo->commissionData.vendorId);
ChipLogProgress(Discovery, "\tProduct ID:\t\t%u", dnsSdInfo->commissionData.productId);
ChipLogProgress(Discovery, "\tCommissioning Mode\t%u", dnsSdInfo->commissionData.commissioningMode);
ChipLogProgress(Discovery, "\tDevice Type\t\t%u", dnsSdInfo->commissionData.deviceType);
ChipLogProgress(Discovery, "\tDevice Name\t\t%s", dnsSdInfo->commissionData.deviceName);
ChipLogProgress(Discovery, "\tRotating Id\t\t%s", rotatingId);
ChipLogProgress(Discovery, "\tPairing Instruction\t%s", dnsSdInfo->commissionData.pairingInstruction);
ChipLogProgress(Discovery, "\tPairing Hint\t\t%u", dnsSdInfo->commissionData.pairingHint);
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().HasValue())
{
ChipLogProgress(Discovery, "\tMrp Interval idle\t%u",
dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().Value().count());
}
else
{
ChipLogProgress(Discovery, "\tMrp Interval idle\tNot present");
}
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().HasValue())
{
ChipLogProgress(Discovery, "\tMrp Interval active\t%u",
dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().Value().count());
}
else
{
ChipLogProgress(Discovery, "\tMrp Interval active\tNot present");
}
ChipLogProgress(Discovery, "\tSupports TCP\t\t%d", dnsSdInfo->resolutionData.supportsTcp);
for (unsigned j = 0; j < dnsSdInfo->resolutionData.numIPs; ++j)
{
char buf[Inet::IPAddress::kMaxStringLength];
dnsSdInfo->resolutionData.ipAddress[j].ToString(buf);
ChipLogProgress(Discovery, "\tAddress %d:\t\t%s", j, buf);
}
}
}

bool pychip_DeviceController_GetIPForDiscoveredDevice(Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
uint32_t len)
{
const Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(idx);
if (dnsSdInfo == nullptr)
{
return false;
}
// TODO(cecille): Select which one we actually want.
if (dnsSdInfo->resolutionData.ipAddress[0].ToString(addrStr, len) == addrStr)
{
return true;
}
return false;
}
}
71 changes: 1 addition & 70 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <inet/IPAddress.h>
#include <lib/core/CHIPTLV.h>
#include <lib/dnssd/Resolver.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPMem.h>
Expand Down Expand Up @@ -549,76 +550,6 @@ ChipError::StorageType pychip_DeviceController_OpenCommissioningWindow(chip::Con
return CHIP_ERROR_INVALID_ARGUMENT.AsInteger();
}

void pychip_DeviceController_PrintDiscoveredDevices(chip::Controller::DeviceCommissioner * devCtrl)
{
for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
{
const chip::Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
if (dnsSdInfo == nullptr)
{
continue;
}
char rotatingId[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
Encoding::BytesToUppercaseHexString(dnsSdInfo->commissionData.rotatingId, dnsSdInfo->commissionData.rotatingIdLen,
rotatingId, sizeof(rotatingId));

ChipLogProgress(Discovery, "Commissionable Node %d", i);
ChipLogProgress(Discovery, "\tInstance name:\t\t%s", dnsSdInfo->commissionData.instanceName);
ChipLogProgress(Discovery, "\tHost name:\t\t%s", dnsSdInfo->resolutionData.hostName);
ChipLogProgress(Discovery, "\tPort:\t\t\t%u", dnsSdInfo->resolutionData.port);
ChipLogProgress(Discovery, "\tLong discriminator:\t%u", dnsSdInfo->commissionData.longDiscriminator);
ChipLogProgress(Discovery, "\tVendor ID:\t\t%u", dnsSdInfo->commissionData.vendorId);
ChipLogProgress(Discovery, "\tProduct ID:\t\t%u", dnsSdInfo->commissionData.productId);
ChipLogProgress(Discovery, "\tCommissioning Mode\t%u", dnsSdInfo->commissionData.commissioningMode);
ChipLogProgress(Discovery, "\tDevice Type\t\t%u", dnsSdInfo->commissionData.deviceType);
ChipLogProgress(Discovery, "\tDevice Name\t\t%s", dnsSdInfo->commissionData.deviceName);
ChipLogProgress(Discovery, "\tRotating Id\t\t%s", rotatingId);
ChipLogProgress(Discovery, "\tPairing Instruction\t%s", dnsSdInfo->commissionData.pairingInstruction);
ChipLogProgress(Discovery, "\tPairing Hint\t\t%u", dnsSdInfo->commissionData.pairingHint);
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().HasValue())
{
ChipLogProgress(Discovery, "\tMrp Interval idle\t%u",
dnsSdInfo->resolutionData.GetMrpRetryIntervalIdle().Value().count());
}
else
{
ChipLogProgress(Discovery, "\tMrp Interval idle\tNot present");
}
if (dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().HasValue())
{
ChipLogProgress(Discovery, "\tMrp Interval active\t%u",
dnsSdInfo->resolutionData.GetMrpRetryIntervalActive().Value().count());
}
else
{
ChipLogProgress(Discovery, "\tMrp Interval active\tNot present");
}
ChipLogProgress(Discovery, "\tSupports TCP\t\t%d", dnsSdInfo->resolutionData.supportsTcp);
for (unsigned j = 0; j < dnsSdInfo->resolutionData.numIPs; ++j)
{
char buf[chip::Inet::IPAddress::kMaxStringLength];
dnsSdInfo->resolutionData.ipAddress[j].ToString(buf);
ChipLogProgress(Discovery, "\tAddress %d:\t\t%s", j, buf);
}
}
}

bool pychip_DeviceController_GetIPForDiscoveredDevice(chip::Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
uint32_t len)
{
const chip::Dnssd::DiscoveredNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(idx);
if (dnsSdInfo == nullptr)
{
return false;
}
// TODO(cecille): Select which one we actually want.
if (dnsSdInfo->resolutionData.ipAddress[0].ToString(addrStr, len) == addrStr)
{
return true;
}
return false;
}

ChipError::StorageType
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DevicePairingDelegate_OnPairingCompleteFunct callback)
Expand Down
4 changes: 4 additions & 0 deletions src/controller/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ features, read the following guides:

- [Working with Python CHIP Controller](../../../docs/guides/python_chip_controller_building.md)
- [Using Python CHIP Controller advanced features](../../../docs/guides/python_chip_controller_advanced_usage.md)

## Recent updates

- Commissionable node discovery API
Loading

0 comments on commit 0460bba

Please sign in to comment.