From 9fe6acd7d3fdbf839b72fc942461f09d8884c37b Mon Sep 17 00:00:00 2001 From: Chirag Atal Date: Mon, 23 Aug 2021 11:41:49 +0530 Subject: [PATCH] app_qrcode: Added qrcode to be displayed on the device console for commissioning. qrcode: Using the qrcode component from esp-idf/examples/common_components. --- examples/common/app_qrcode/CMakeLists.txt | 3 + examples/common/app_qrcode/app_qrcode.cpp | 186 +++++++++++++++++++ examples/common/app_qrcode/app_qrcode.h | 30 +++ examples/light/CMakeLists.txt | 1 + examples/light/main/CMakeLists.txt | 2 +- examples/light/main/app_main.cpp | 2 + examples/rainmaker_light/CMakeLists.txt | 1 + examples/rainmaker_light/main/CMakeLists.txt | 2 +- examples/rainmaker_light/main/app_main.cpp | 2 + 9 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 examples/common/app_qrcode/CMakeLists.txt create mode 100644 examples/common/app_qrcode/app_qrcode.cpp create mode 100644 examples/common/app_qrcode/app_qrcode.h diff --git a/examples/common/app_qrcode/CMakeLists.txt b/examples/common/app_qrcode/CMakeLists.txt new file mode 100644 index 000000000..8e8a763ee --- /dev/null +++ b/examples/common/app_qrcode/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS app_qrcode.cpp + INCLUDE_DIRS . + PRIV_REQUIRES chip bt esp32_mbedtls qrcode) diff --git a/examples/common/app_qrcode/app_qrcode.cpp b/examples/common/app_qrcode/app_qrcode.cpp new file mode 100644 index 000000000..ca7e2274d --- /dev/null +++ b/examples/common/app_qrcode/app_qrcode.cpp @@ -0,0 +1,186 @@ +/* + 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 + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::chip; +using namespace ::chip::DeviceLayer; + +#define QRCODE_BASE_URL "https://dhrishi.github.io/connectedhomeip/qrcode.html" +static const char *TAG = "app_qrcode"; + +esp_err_t app_qrcode_get_payload(char **qrcode_text, char **short_manual_code_text, char **long_manual_code_text) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + esp_err_t ret = ESP_OK; + uint16_t discriminator; + uint32_t setup_pin_code; + uint16_t vendor_id; + uint16_t product_id; + SetupPayload payload; + std::string qrcode_payload; + std::string short_manual_code_payload; + std::string long_manual_code_payload; + + /* Get details */ + err = ConfigurationMgr().GetSetupDiscriminator(discriminator); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(TAG, "Couldn't get discriminator: %s", ErrorStr(err)); + return ESP_FAIL; + } + + err = ConfigurationMgr().GetSetupPinCode(setup_pin_code); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(TAG, "Couldn't get setup_pin_code: %s", ErrorStr(err)); + return ESP_FAIL; + } + + err = ConfigurationMgr().GetVendorId(vendor_id); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(TAG, "Couldn't get vendor_id: %s", ErrorStr(err)); + return ESP_FAIL; + } + + err = ConfigurationMgr().GetProductId(product_id); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(TAG, "Couldn't get product_id: %s", ErrorStr(err)); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Setup discriminator: %u (0x%x)", discriminator, discriminator); + ESP_LOGI(TAG, "Setup PIN code: %u (0x%x)", setup_pin_code, setup_pin_code); + ESP_LOGI(TAG, "Vendor ID: %u (0x%x)", vendor_id, vendor_id); + ESP_LOGI(TAG, "Product ID: %u (0x%x)", product_id, product_id); + + /* Set details */ + payload.version = 0; + payload.discriminator = discriminator; + payload.setUpPINCode = setup_pin_code; + payload.rendezvousInformation = RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE); + payload.vendorID = vendor_id; + payload.productID = product_id; + + /* Change format and alloc for qrcode */ + QRCodeSetupPayloadGenerator qrcode_generator(payload); + err = qrcode_generator.payloadBase38Representation(qrcode_payload); + if (err == CHIP_NO_ERROR) { + *qrcode_text = (char *)calloc(1, qrcode_payload.length() + 1); + if (*qrcode_text) { + strcpy(*qrcode_text, qrcode_payload.c_str()); + } + } else { + ESP_LOGE(TAG, "Couldn't get qrcode payload string %s", ErrorStr(err)); + ret = ESP_FAIL; + } + + /* Change format and alloc for short manual code. This can be used for 'non qrcode' devices. */ + ManualSetupPayloadGenerator short_manual_code_generator(payload); + err = short_manual_code_generator.payloadDecimalStringRepresentation(short_manual_code_payload); + if (err == CHIP_NO_ERROR) { + *short_manual_code_text = (char *)calloc(1, short_manual_code_payload.length() + 1); + if (*short_manual_code_text) { + strcpy(*short_manual_code_text, short_manual_code_payload.c_str()); + } + } else { + ESP_LOGE(TAG, "Couldn't get short manual code payload string %s", ErrorStr(err)); + ret = ESP_FAIL; + } + + /* Change format and alloc for long manual code. This can be used for 'non qrcode' devices. */ + /* Just adding this extra commissioning flow to the payload. */ + payload.commissioningFlow = CommissioningFlow::kCustom; + ManualSetupPayloadGenerator long_manual_code_generator(payload); + err = long_manual_code_generator.payloadDecimalStringRepresentation(long_manual_code_payload); + if (err == CHIP_NO_ERROR) { + *long_manual_code_text = (char *)calloc(1, long_manual_code_payload.length() + 1); + if (*long_manual_code_text) { + strcpy(*long_manual_code_text, long_manual_code_payload.c_str()); + } + } else { + ESP_LOGE(TAG, "Couldn't get long manual code payload string %s", ErrorStr(err)); + ret = ESP_FAIL; + } + + return ret; +} + +esp_err_t app_qrcode_print() +{ + /* Get */ + char *qrcode_text = NULL; + char *short_manual_code_text = NULL; + char *long_manual_code_text = NULL; + bool manual_code_exists = false; + esp_err_t err = app_qrcode_get_payload(&qrcode_text, &short_manual_code_text, &long_manual_code_text); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Error getting payload %d", err); + } + + /* Manual code */ + if (short_manual_code_text || long_manual_code_text) { + /* This flag is just used for the print at the end */ + manual_code_exists = true; + } + + /* Short manual code */ + if (short_manual_code_text) { + /* Print */ + ESP_LOGI(TAG, "Short manual code: %s", short_manual_code_text); + + /* Free */ + free(short_manual_code_text); + } else { + ESP_LOGE(TAG, "Error getting short manual code text"); + err = ESP_FAIL; + } + + /* Long manual code */ + if (long_manual_code_text) { + /* Print */ + ESP_LOGI(TAG, "Long manual code: %s", long_manual_code_text); + + /* Free */ + free(long_manual_code_text); + } else { + ESP_LOGE(TAG, "Error getting long manual code text"); + err = ESP_FAIL; + } + + /* QR code */ + if (qrcode_text) { + /* Print */ + ESP_LOGI(TAG, "Scan this QR code from the Matter phone app for Commissioning."); + esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT(); + /* Changing the error tolerance to MED. This increases the size of the qr code and makes it more detailed. The default is set to LOW and sometimes the qr code scanner is not able to recognize that. */ + cfg.qrcode_ecc_level = ESP_QRCODE_ECC_MED; + esp_qrcode_generate(&cfg, qrcode_text); + ESP_LOGI(TAG, "If QR code is not visible, copy paste the URL in a browser: %s?data=%s", QRCODE_BASE_URL, qrcode_text); + + /* Free */ + free(qrcode_text); + } else { + ESP_LOGE(TAG, "Error getting qrcode text"); + err = ESP_FAIL; + } + + if (manual_code_exists) { + ESP_LOGI(TAG, "In case QR code is not supported, manual code mentioned above can be entered in the Matter phone app for Commissioning"); + } + + return err; +} diff --git a/examples/common/app_qrcode/app_qrcode.h b/examples/common/app_qrcode/app_qrcode.h new file mode 100644 index 000000000..59ce5dd7c --- /dev/null +++ b/examples/common/app_qrcode/app_qrcode.h @@ -0,0 +1,30 @@ +/* + 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 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Print the QR code for commissioning + * + * Fetch the QR code details for commissioning from Matter and print it on the console. + * Also print the manual code if QR code is not supported. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t app_qrcode_print(); + +#ifdef __cplusplus +} +#endif diff --git a/examples/light/CMakeLists.txt b/examples/light/CMakeLists.txt index fcbf1796a..e3a56fbf7 100644 --- a/examples/light/CMakeLists.txt +++ b/examples/light/CMakeLists.txt @@ -27,6 +27,7 @@ include($ENV{ESP_MATTER_DEVICE_PATH}/esp_matter_device.cmake) set(EXTRA_COMPONENT_DIRS "../common" + "${IDF_PATH}/examples/common_components" "${MATTER_SDK_PATH}/config/esp32/components" "${ESP_MATTER_PATH}/components" "${ESP_MATTER_PATH}/device_hal/device" diff --git a/examples/light/main/CMakeLists.txt b/examples/light/main/CMakeLists.txt index 1f612d093..630ab12b3 100644 --- a/examples/light/main/CMakeLists.txt +++ b/examples/light/main/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" "${MATTER_SDK_PATH}/src") -set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver) +set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver app_qrcode) if ("${IDF_TARGET}" STREQUAL "esp32h2") list(APPEND PRIV_REQUIRES_LIST openthread mynewt_nimble) diff --git a/examples/light/main/app_main.cpp b/examples/light/main/app_main.cpp index 9b1ce8eb1..f5af502f5 100644 --- a/examples/light/main/app_main.cpp +++ b/examples/light/main/app_main.cpp @@ -11,6 +11,7 @@ #include "esp_matter.h" #include "esp_matter_standard.h" #include "app_driver.h" +#include "app_qrcode.h" #include "app_matter.h" #include "app_constants.h" @@ -103,6 +104,7 @@ extern "C" void app_main() /* Initialize chip */ ESP_ERROR_CHECK(app_matter_init()); + app_qrcode_print(); /* Set the default attribute values */ esp_matter_attribute_notify(APP_MAIN_NAME, ESP_MATTER_ENDPOINT_LIGHT, ESP_MATTER_ATTR_POWER, esp_matter_bool(DEFAULT_POWER)); diff --git a/examples/rainmaker_light/CMakeLists.txt b/examples/rainmaker_light/CMakeLists.txt index 7ff411f2e..c704587b2 100644 --- a/examples/rainmaker_light/CMakeLists.txt +++ b/examples/rainmaker_light/CMakeLists.txt @@ -29,6 +29,7 @@ include($ENV{ESP_MATTER_DEVICE_PATH}/esp_matter_device.cmake) set(EXTRA_COMPONENT_DIRS "../common" + "${IDF_PATH}/examples/common_components" "${MATTER_SDK_PATH}/config/esp32/components" "${ESP_MATTER_PATH}/components" "${ESP_MATTER_PATH}/device_hal/device" diff --git a/examples/rainmaker_light/main/CMakeLists.txt b/examples/rainmaker_light/main/CMakeLists.txt index d880f735f..23f316a49 100644 --- a/examples/rainmaker_light/main/CMakeLists.txt +++ b/examples/rainmaker_light/main/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" "${MATTER_SDK_PATH}/src") -set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver esp_rainmaker) +set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver app_qrcode esp_rainmaker) idf_component_register(SRC_DIRS ${SRC_DIRS_LIST} PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} diff --git a/examples/rainmaker_light/main/app_main.cpp b/examples/rainmaker_light/main/app_main.cpp index fcbffc1b0..81c54d254 100644 --- a/examples/rainmaker_light/main/app_main.cpp +++ b/examples/rainmaker_light/main/app_main.cpp @@ -11,6 +11,7 @@ #include "esp_matter.h" #include "esp_matter_standard.h" #include "app_driver.h" +#include "app_qrcode.h" #include "app_matter.h" #include "app_constants.h" #include "app_rainmaker.h" @@ -106,6 +107,7 @@ extern "C" void app_main() /* Initialize chip */ ESP_ERROR_CHECK(app_matter_init()); + app_qrcode_print(); /* Initialize rainmaker */ app_rainmaker_init();