Skip to content

Commit

Permalink
Merge branch 'controller/show_dynamic_qrcode' into 'master'
Browse files Browse the repository at this point in the history
show dynamic QR code on screen for matter_controller_with_touchscreen exmaple.

See merge request app-frameworks/esp-rainmaker!429
  • Loading branch information
dhrishi committed May 13, 2024
2 parents 43135c7 + e0715b2 commit 92a5435
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 16 deletions.
2 changes: 2 additions & 0 deletions examples/matter/matter_controller/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,5 @@ CONFIG_LWIP_IPV6_NUM_ADDRESSES=6

# Increase attribute buffer largest
CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST=2050

CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE=y
8 changes: 1 addition & 7 deletions examples/matter/matter_controller_with_touchscreen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@

### [Claiming device certificates](../README.md#claiming-device-certificates)

### Generating the factory nvs binary

For this example, make sure to configure the passcode as 125 and set the discriminator to 521 to match the QR code on UI. The command is:
```
$ cd $ESP_MATTER_PATH/tools/mfg_tool
$ ./mfg_tool.py -v 0x131B -p 0x2 --passcode 125 --discriminator 521 -cd $RMAKER_PATH/examples/matter/mfg/cd_131B_0002.der --csv $RMAKER_PATH/examples/matter/mfg/keys.csv --mcsv $RMAKER_PATH/examples/matter/mfg/master.csv
```
### [Generating the factory nvs binary](../README.md#generating-the-factory-nvs-binary)

### Building the example

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
set(ldfragments linker.lf)

set(SRC_DIRS_LIST "."
"./box"
"./box/gui"
"./box/gui/image")

set(PRIV_INCLUDE_DIRS_LIST "."
"./box"
"./box/gui")

if (CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER)
list(APPEND SRC_DIRS_LIST "./dynamic_qrcode")
list(APPEND PRIV_INCLUDE_DIRS_LIST "./dynamic_qrcode")
endif()

idf_component_register(
SRC_DIRS
"."
"./box"
"./box/gui"
"./box/gui/image"
PRIV_INCLUDE_DIRS
"."
"./box"
"./box/gui"
SRC_DIRS ${SRC_DIRS_LIST}
PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST}
LDFRAGMENTS "${ldfragments}")

target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
#include "app_matter_ctrl.h"
#include "ui_matter_ctrl.h"

#if CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER
#include <esp_matter_providers.h>
#include "dynamic_qrcode.h"
#endif

using namespace esp_matter;
using namespace esp_matter::attribute;
using namespace esp_matter::cluster;
Expand Down Expand Up @@ -194,6 +199,10 @@ esp_err_t app_matter_pre_rainmaker_start()

esp_err_t app_matter_start()
{
#if CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER
esp_matter::set_custom_commissionable_data_provider(&DynamicPasscodeCommissionableDataProvider::GetInstance());
#endif

esp_err_t err = esp_matter::start(app_event_cb);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Matter start failed: %d", err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include "esp_log.h"
#include "lvgl.h"

#if CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER
#include "dynamic_qrcode.h"
#endif

static const char *TAG = "ui_matter_ctrl";

static bool IsCommission = false;
Expand Down Expand Up @@ -288,7 +292,11 @@ void ui_matter_ctrl_start(void (*fn)(void))
if (!IsCommission) {
QRcode = lv_qrcode_create(g_page, qrcode_width, lv_color_black(), lv_color_white());
lv_obj_align(QRcode, LV_ALIGN_TOP_MID, 0, qrcode_align_y);
#ifdef CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER
const char *qrcode_data = DynamicPasscodeCommissionableDataProvider::GetInstance().GetDynamicQRcodeStr();
#else
const char *qrcode_data = "MT:U9VJ0EPJ01ZD6100000";
#endif
ESP_LOGI(TAG, "QR Data: %s", qrcode_data);
lv_qrcode_update(QRcode, qrcode_data, strlen(qrcode_data));
lv_label_set_text_static(g_hint_label, "Scan the QR code on your phone");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/

#include <app/server/OnboardingCodesUtil.h>
#include <crypto/CHIPCryptoPAL.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <protocols/secure_channel/PASESession.h>
#include <setup_payload/SetupPayload.h>

#include "dynamic_qrcode.h"
#include "esp_log.h"

static const char *TAG = "dynamic_qrcode";

CHIP_ERROR DynamicPasscodeCommissionableDataProvider::GetSetupDiscriminator(uint16_t &setupDiscriminator)
{
if (discriminator >= 4096) {
chip::Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&discriminator), sizeof(discriminator));
discriminator %= 4096;
}
setupDiscriminator = discriminator;
return CHIP_NO_ERROR;
}

CHIP_ERROR DynamicPasscodeCommissionableDataProvider::GetSpake2pIterationCount(uint32_t &iterationCount)
{
return chip::DeviceLayer::Internal::ESP32Config::ReadConfigValue(
chip::DeviceLayer::Internal::ESP32Config::kConfigKey_Spake2pIterationCount, iterationCount);
}

CHIP_ERROR DynamicPasscodeCommissionableDataProvider::GetSpake2pSalt(chip::MutableByteSpan &saltBuf)
{
static constexpr size_t kSpake2pSalt_MaxBase64Len =
BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1;
CHIP_ERROR err = CHIP_NO_ERROR;
char saltB64[kSpake2pSalt_MaxBase64Len] = {0};
size_t saltB64Len = 0;
err = chip::DeviceLayer::Internal::ESP32Config::ReadConfigValueStr(
chip::DeviceLayer::Internal::ESP32Config::kConfigKey_Spake2pSalt, saltB64, sizeof(saltB64), saltB64Len);
ReturnErrorOnFailure(err);
size_t saltLen = chip::Base64Decode32(saltB64, saltB64Len, reinterpret_cast<uint8_t *>(saltB64));
ReturnErrorCodeIf(saltLen > saltBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(saltBuf.data(), saltB64, saltLen);
saltBuf.reduce_size(saltLen);
return CHIP_NO_ERROR;
}

CHIP_ERROR DynamicPasscodeCommissionableDataProvider::GetSpake2pVerifier(chip::MutableByteSpan &verifierBuf,
size_t &verifierLen)
{
chip::Crypto::Spake2pVerifier verifier;
uint32_t iterationCount = 0;
uint32_t setupPasscode = 0;
uint8_t saltData[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length] = {0};
chip::MutableByteSpan saltBuf(saltData);
ReturnErrorOnFailure(DynamicPasscodeCommissionableDataProvider::GetSpake2pIterationCount(iterationCount));
ReturnErrorOnFailure(DynamicPasscodeCommissionableDataProvider::GetSetupPasscode(setupPasscode));
ReturnErrorOnFailure(DynamicPasscodeCommissionableDataProvider::GetSpake2pSalt(saltBuf));
CHIP_ERROR err = chip::PASESession::GeneratePASEVerifier(verifier, iterationCount, saltBuf, false, setupPasscode);
ReturnErrorOnFailure(err);
err = verifier.Serialize(verifierBuf);
verifierLen = verifierBuf.size();
ReturnErrorOnFailure(err);
return CHIP_NO_ERROR;
}

CHIP_ERROR DynamicPasscodeCommissionableDataProvider::GetSetupPasscode(uint32_t &setupPasscode)
{
if (passcode == 0) {
while (!chip::SetupPayload::IsValidSetupPIN(passcode)) {
chip::Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&passcode), sizeof(passcode));
passcode = (passcode % chip::kSetupPINCodeMaximumValue) + 1;
}
}
setupPasscode = passcode;
return CHIP_NO_ERROR;
}

const char *DynamicPasscodeCommissionableDataProvider::GetDynamicQRcodeStr()
{
static bool hasInitialized = false;
if (hasInitialized) {
return dynamicQrcodeData;
}
CHIP_ERROR ret = CHIP_NO_ERROR;
chip::PayloadContents payload;
uint16_t setupDiscriminator = 0;
char qrCodeData[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1] = {0};
chip::MutableCharSpan qrCodeBuf(qrCodeData);
chip::RendezvousInformationFlags rendezvous(chip::RendezvousInformationFlag::kSoftAP,
chip::RendezvousInformationFlag::kBLE);
chip::DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(payload.vendorID);
chip::DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(payload.productID);
GetInstance().GetSetupDiscriminator(setupDiscriminator);
payload.discriminator.SetLongValue(setupDiscriminator);
GetInstance().GetSetupPasscode(payload.setUpPINCode);
payload.rendezvousInformation.SetValue(rendezvous);
ESP_LOGI(TAG, "DeviceInfo vid:%d pid:%d discriminator:%d passcode:%d", payload.vendorID, payload.productID,
payload.discriminator.GetLongValue(), payload.setUpPINCode);
ret = GetQRCode(qrCodeBuf, payload);
for (size_t i = 0; i < qrCodeBuf.size(); ++i) {
*(dynamicQrcodeData + i) = *(qrCodeBuf.data() + i);
}
*(dynamicQrcodeData + qrCodeBuf.size()) = '\0';

if (ret != CHIP_NO_ERROR) {
return nullptr;
}
hasInitialized = true;
return dynamicQrcodeData;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/

#pragma once

#include <esp_err.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <platform/ESP32/ESP32FactoryDataProvider.h>
#include <lib/support/Span.h>

class DynamicPasscodeCommissionableDataProvider : public chip::DeviceLayer::CommissionableDataProvider
{
public:
// ===== Members functions that implement the CommissionableDataProvider
CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override;
CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override { return CHIP_ERROR_NOT_IMPLEMENTED; }
CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override;
CHIP_ERROR GetSpake2pSalt(chip::MutableByteSpan & saltBuf) override;
CHIP_ERROR GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & verifierLen) override;
CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override;
CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override { return CHIP_ERROR_NOT_IMPLEMENTED; }
static DynamicPasscodeCommissionableDataProvider &GetInstance()
{
static DynamicPasscodeCommissionableDataProvider sCommissionableDataProvider;
return sCommissionableDataProvider;
}
const char *GetDynamicQRcodeStr();

private:
DynamicPasscodeCommissionableDataProvider() :
chip::DeviceLayer::CommissionableDataProvider() {}
uint32_t passcode = 0;
uint16_t discriminator = 4096;
char dynamicQrcodeData[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1] = {0};
};
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,8 @@ CONFIG_IDF_TARGET="esp32s3"

# Select one of the boards
CONFIG_BSP_BOARD_ESP32_S3_BOX_3=y

# Enable custom commission data to use dynamic qrcode
CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER=y

CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE=y

0 comments on commit 92a5435

Please sign in to comment.