Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How does the bridge device use the dynamic pairing code? (CON-1435) #1173

Closed
LinKvFM opened this issue Nov 27, 2024 · 9 comments
Closed

How does the bridge device use the dynamic pairing code? (CON-1435) #1173

LinKvFM opened this issue Nov 27, 2024 · 9 comments

Comments

@LinKvFM
Copy link

LinKvFM commented Nov 27, 2024

How to use the dynamic pairing code and how to actively open the commission window? These questions can help me update the matter through OTA in the mass-produced products.

@github-actions github-actions bot changed the title How does the bridge device use the dynamic pairing code? How does the bridge device use the dynamic pairing code? (CON-1435) Nov 27, 2024
@shubhamdp
Copy link
Contributor

Can you please share more insights on your problem. What sort of device are you upgrading, is this like pre-Matter device upgrading to Matter functionality?

If you are looking for device to display the onboarding code then that has been addressed in #1128 (comment). You can find relevant information in #1126.

@LinKvFM
Copy link
Author

LinKvFM commented Dec 4, 2024

We have a HomeKit-compatible product that has been mass-produced. I hope it can also be compatible with matter. I want to expand the functionality of matter through OTA upgrades, and use the app to display the dynamic pairing code and open the commission window. Now I don’t know how to develop it. Are there any interfaces I can try to call?

@LinKvFM
Copy link
Author

LinKvFM commented Dec 4, 2024

This is a bridge type device. How to implement these functions on the device side?#1173 (comment)

@shubhamdp
Copy link
Contributor

Sorry @LinKvFM for the delayed response.

We have a HomeKit-compatible product that has been mass-produced

I think this will continue to work with older firmware.

I want to expand the functionality of matter through OTA upgrades

I'd suggest you go through Core Matter Specification section 5.8. In-field Upgrade to Matter. For upgrades, you would need some sort of secure communication channel with device to program the DAC and onboarding data.
If you have an application to onboard the pre-Matter device then that can be used to display onboarding payload. You can either hardcode the per device onboarding codes or generate the dynamic ones as described in #1128 (comment) and #1126.

If device do not have any interface to display the QR Code then I think your phone app can be used.

@LinKvFM
Copy link
Author

LinKvFM commented Dec 14, 2024

@shubhamdp Every time I open the commissioning window, the pairing code is the same. How can I change it?
This is my code: Discriminator and Salt are random

int open_enhanced_commissioning_window(char* qrCode, char* pairingCode)
{
    if (qrCode == NULL || pairingCode == NULL)
    {
        return -1;
    }
    chip::System::Clock::Seconds32 sec = chip::System::Clock::Seconds32(600);
    chip::CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
    constexpr auto fabricIndex                 = static_cast<chip::FabricIndex>(1);
    constexpr auto vendorId                    = static_cast<chip::VendorId>(0xFFF3);
    CHIP_ERROR err = CHIP_NO_ERROR;
    dynamic_commissionable_data_provider dyCommissionDp;
    uint16_t discriminator = 0;
    uint32_t iterationCount = 0;
    uint32_t setupPasscode = 0;
    dyCommissionDp.GetSetupDiscriminator(discriminator); //random
    // dyCommissionDp.GetSpake2pIterationCount(iterationCount);

    uint8_t salt[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length] = {0};

    chip::MutableByteSpan saltSpan(salt, chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
    dyCommissionDp.GetSetupPasscode(setupPasscode);
    ESP_LOGW(TAG, "setupPasscode: [%ld]", setupPasscode);
    dyCommissionDp.GetSpake2pIterationCount(iterationCount);
    dyCommissionDp.GetSpake2pSalt(saltSpan); //random

    chip::Crypto::Spake2pVerifier verifier;
    verifier.Generate(iterationCount, saltSpan, setupPasscode);


    chip::DeviceLayer::PlatformMgr().LockChipStack();
    // commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), chip::CommissioningWindowAdvertisement::kAllSupported);
    err = commissionMgr.OpenEnhancedCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), discriminator, verifier, iterationCount, saltSpan, fabricIndex, vendorId);
    chip::DeviceLayer::PlatformMgr().UnlockChipStack();
    if (err != CHIP_NO_ERROR)
    {
        return -1;
    }
    
    chip::RendezvousInformationFlags aRendezvousFlags = chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE);
    PrintOnboardingCodes(aRendezvousFlags);

    chip::PayloadContents payload;
    GetPayloadContents(payload, aRendezvousFlags);

    char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
    chip::MutableCharSpan qrCode(payloadBuffer);
    if(GetQRCode(qrCode, payload) == CHIP_NO_ERROR ){
        ESP_LOGW(TAG, "SetupQRCode: [%s]", qrCode.data());
        memcpy(qrCode, qrCode.data(), strlen(qrCode.data()));
    }else{
        return -1;
    }

    chip::MutableCharSpan manualPairingCode(payloadBuffer);
    if (GetManualPairingCode(manualPairingCode, payload) == CHIP_NO_ERROR)
    {
        ESP_LOGW(TAG, "Manual pairing code: [%s]", manualPairingCode.data());
        memcpy(pairingCode, manualPairingCode.data(), strlen(manualPairingCode.data()));
    }else{
        return -1;
    }

    return 0;
}

@LinKvFM
Copy link
Author

LinKvFM commented Dec 14, 2024

An error occurred when the above code ran to verifier.Generate(iterationCount, saltSpan, setupPasscode);
截图 2024-12-14 15-40-15

@LinKvFM
Copy link
Author

LinKvFM commented Dec 19, 2024

I made the changes again, but another problem occurred. I can print the dynamic pairing code, but I can't use it to pair. Every time I use the original 34970112332 to pair.

int open_enhanced_commissioning_window(char* qr_Code, char* pairingCode)
{
    if (qr_Code == NULL || pairingCode == NULL)
    {
        return -1;
    }
    chip::System::Clock::Seconds32 sec = chip::System::Clock::Seconds32(600);
    chip::CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
    constexpr auto fabricIndex                 = static_cast<chip::FabricIndex>(1);
    constexpr auto vendorId                    = static_cast<chip::VendorId>(0xFFF1);

    CHIP_ERROR err = CHIP_NO_ERROR;
    dynamic_commissionable_data_provider dyCommissionDp;
    uint16_t discriminator = 0;
    uint32_t iterationCount = 0;
    uint32_t setupPasscode = 0;

    dyCommissionDp.GetSetupDiscriminator(discriminator);
    // dyCommissionDp.GetSpake2pIterationCount(iterationCount);

    uint8_t salt[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length] = {0};

    chip::MutableByteSpan saltSpan(salt, chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
    dyCommissionDp.GetSetupPasscode(setupPasscode);
    ESP_LOGW(TAG, "setupPasscode: [%ld]", setupPasscode);
    dyCommissionDp.GetSpake2pIterationCount(iterationCount);
    dyCommissionDp.GetSpake2pSalt(saltSpan);

    chip::Crypto::Spake2pVerifier verifier;
    vTaskDelay(100 / portTICK_PERIOD_MS);
    verifier.Generate(iterationCount, saltSpan, setupPasscode);
    vTaskDelay(300 / portTICK_PERIOD_MS);
    if (commissionMgr.IsCommissioningWindowOpen())
    {
        commissionMgr.CloseCommissioningWindow();
    }
    chip::DeviceLayer::PlatformMgr().LockChipStack();
    // commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), chip::CommissioningWindowAdvertisement::kAllSupported);
    err = commissionMgr.OpenEnhancedCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), discriminator, verifier, iterationCount, saltSpan, fabricIndex, vendorId);
    chip::DeviceLayer::PlatformMgr().UnlockChipStack();
    if (err != CHIP_NO_ERROR)
    {
        return -1;
    }

    chip::SetupPayload payload;
    payload.discriminator.SetLongValue(discriminator);  
    payload.setUpPINCode = setupPasscode; 
    payload.vendorID = 0xFFF1; 
    payload.productID = 0xA001; 
    payload.rendezvousInformation.SetValue(RendezvousInformationFlags(chip::RendezvousInformationFlag::kOnNetwork));

    PrintOnboardingCodes(payload);

    chip::QRCodeSetupPayloadGenerator generator(payload);
    std::string qrCode;
    err = generator.payloadBase38Representation(qrCode);

    if (err == CHIP_NO_ERROR) {
        ESP_LOGW(TAG,"SetupQRCode: %s\n", qrCode.c_str());
        memcpy(qr_Code, qrCode.c_str(), strlen(qrCode.c_str()));
    } else {
        ESP_LOGW(TAG,"Failed to generate QR code: %s\n", ErrorStr(err));
        commissionMgr.CloseCommissioningWindow();
        return -1;
    }

    std::string manualPairingCode;
    err = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode);

    if (err == CHIP_NO_ERROR) {
        ESP_LOGW(TAG,"ManualPairingCode: %s\n", manualPairingCode.c_str());
        memcpy(pairingCode, manualPairingCode.c_str(), strlen(manualPairingCode.c_str())>=64?63:strlen(manualPairingCode.c_str()));
    } else {
        ESP_LOGW(TAG,"Failed to generate manual pairing code: %s\n", ErrorStr(err));
        commissionMgr.CloseCommissioningWindow();
        return -1;
    }
    return 0;
}

@shubhamdp
Copy link
Contributor

@LinKvFM sorry for the delayed response.

If you see the way you have declared, it will be vanished once it goes out of scope. It should either be defined as global or static or dynamically allocated which lasts till the application lifetime.

dynamic_commissionable_data_provider dyCommissionDp;

In light_switch example it is defined as global. (ref: https://github.com/espressif/esp-matter/blob/main/examples/light_switch/main/app_main.cpp#L36)

Also, I think you forgot to set the commissionable data provider using esp_matter::set_custom_commissionable_data_provider() API? Please find the usage here. (ref: https://github.com/espressif/esp-matter/blob/main/examples/light_switch/main/app_main.cpp#L136)

I'd suggest you to please take a look at light_switch app for how to implement the dynamic commissionable data provider.

And as far as payload generation goes, LGTM! But, I'd still suggest you to cross check it using setup payload parser. eg: chip-tool payload parse-setup-payload <payload>.

@LinKvFM
Copy link
Author

LinKvFM commented Dec 20, 2024

Thanks, the problem has been solved.

@LinKvFM LinKvFM closed this as completed Dec 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants