From 071cec39468f6474003e064502ab4e6ae7c54720 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Sat, 10 Jul 2021 05:02:55 +0800 Subject: [PATCH] ESP32C3 Support: (#8201) use onboard RGB-LED(WS2812) for status-LED in all-clusters-app add colorcontrol cluster for ESP32C3_DevkitM --- .../all-clusters-app/esp32/CMakeLists.txt | 11 +- examples/all-clusters-app/esp32/README.md | 25 ++++- .../esp32/main/CMakeLists.txt | 8 +- .../esp32/main/DeviceCallbacks.cpp | 36 +++++- .../esp32/main/Kconfig.projbuild | 3 +- .../all-clusters-app/esp32/main/LEDWidget.cpp | 105 +++++++++++++++++- .../esp32/main/include/DeviceCallbacks.h | 3 + .../esp32/main/include/LEDWidget.h | 8 ++ examples/all-clusters-app/esp32/main/main.cpp | 2 +- 9 files changed, 181 insertions(+), 20 deletions(-) diff --git a/examples/all-clusters-app/esp32/CMakeLists.txt b/examples/all-clusters-app/esp32/CMakeLists.txt index 930da3d1be2d3e..9d98e41df4be5c 100644 --- a/examples/all-clusters-app/esp32/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/CMakeLists.txt @@ -24,12 +24,11 @@ set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../common/QRCode" ) if(${IDF_TARGET} STREQUAL "esp32") -set(EXTRA_COMPONENT_DIRS - ${EXTRA_COMPONENT_DIRS} - "${CMAKE_CURRENT_LIST_DIR}/../../common/m5stack-tft/repo/components/tft" - "${CMAKE_CURRENT_LIST_DIR}/../../common/m5stack-tft/repo/components/spidriver" - "${CMAKE_CURRENT_LIST_DIR}/../../common/screen-framework" -) + list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../common/m5stack-tft/repo/components/tft" + "${CMAKE_CURRENT_LIST_DIR}/../../common/m5stack-tft/repo/components/spidriver" + "${CMAKE_CURRENT_LIST_DIR}/../../common/screen-framework") +elseif(${IDF_TARGET} STREQUAL "esp32c3") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/peripherals/rmt/led_strip/components") endif() project(chip-all-clusters-app) diff --git a/examples/all-clusters-app/esp32/README.md b/examples/all-clusters-app/esp32/README.md index a9cab13a1b2476..9ad8ee6c7b906e 100644 --- a/examples/all-clusters-app/esp32/README.md +++ b/examples/all-clusters-app/esp32/README.md @@ -209,11 +209,23 @@ commissioning and cluster control. ### Cluster control -- After successful commissioning, use the OnOff cluster command to control the - OnOff attribute. This allows you to toggle a parameter implemented by the - device to be On or Off. +- After successful commissioning, use the OnOff cluster commands to control + the OnOff attribute. This allows you to toggle a parameter implemented by + the device to be On or Off. - `chip-device-ctrl > zcl OnOff Off 135246 1 0` + `chip-device-ctrl > zcl OnOff Off 135246 1 1` + +- Use the LevelControl cluster commands to control the CurrentLevel attribute. + This allows you to control the brightness of the led. + + `chip-device-ctrl > zcl LevelControl MoveToLevel 135246 1 1 level=10 transitionTime=0 optionMask=0 optionOverride=0` + +- For ESP32C3-DevKitM, use the ColorContorl cluster commands to control the + CurrentHue and CurrentSaturation attribute. This allows you to control the + color of on-board LED. + + `zcl ColorControl MoveToHue 135246 1 1 hue=100 direction=0 transitionTime=0 optionsMask=0 optionsOverride=0` + `zcl ColorControl MoveToSaturation 135245 1 1 saturation=200 transitionTime=0 optionsMask=0 optionsOverride=0` ### Flashing app using script @@ -243,5 +255,6 @@ through the on/off/toggle commands from the `python-controller`. For `M5Stack`, a virtual Green LED on the display is used for the same. If you wish to see the actual effect of the commands on `ESP32-DevKitC`, -`ESP32-WROVER-KIT_V4.1` and `ESP32C3-DevKitM`, you will have to connect an -external LED to GPIO `STATUS_LED_GPIO_NUM`. +`ESP32-WROVER-KIT_V4.1`, you will have to connect an external LED to GPIO +`STATUS_LED_GPIO_NUM`. For `ESP32C3-DevKitM`, the on-board LED will show the +actual effect of the commands. diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 1124c7077833e1..06eb182bcf810d 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -69,13 +69,17 @@ set(SRC_DIRS_LIST ) if(("${CONFIG_DEVICE_TYPE_ESP32_DEVKITC}" STREQUAL "y") OR ("${CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM}" STREQUAL "y")) - set(PRIV_INCLUDE_DIRS_LIST ${PRIV_INCLUDE_DIRS_LIST} - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/common/screen-framework/include") + list(APPEND PRIV_INCLUDE_DIRS_LIST + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/common/screen-framework/include") set(PRIV_REQUIRES_LIST chip QRCode bt) elseif(("${CONFIG_DEVICE_TYPE_M5STACK}" STREQUAL "y") OR ("${CONFIG_DEVICE_TYPE_ESP32_WROVER_KIT}" STREQUAL "y")) set(PRIV_REQUIRES_LIST chip QRCode bt tft spidrier screen-framework) endif() +if("${CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM}" STREQUAL "y") + list(APPEND PRIV_REQUIRES_LIST led_strip) +endif() + idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp index 21be643045fb58..1f549bca131380 100644 --- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp @@ -95,7 +95,11 @@ void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, Cluster case ZCL_LEVEL_CONTROL_CLUSTER_ID: OnLevelControlAttributeChangeCallback(endpointId, attributeId, value); break; - +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + case ZCL_COLOR_CONTROL_CLUSTER_ID: + OnColorControlAttributeChangeCallback(endpointId, attributeId, value); + break; +#endif default: ESP_LOGI(TAG, "Unhandled cluster ID: %d", clusterId); break; @@ -164,6 +168,36 @@ void DeviceCallbacks::OnLevelControlAttributeChangeCallback(EndpointId endpointI return; } +// Currently we only support ColorControl cluster for ESP32C3_DEVKITM which has an on-board RGB-LED +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM +void DeviceCallbacks::OnColorControlAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == ZCL_COLOR_CONTROL_CURRENT_HUE_ATTRIBUTE_ID || + attributeId == ZCL_COLOR_CONTROL_CURRENT_SATURATION_ATTRIBUTE_ID, + ESP_LOGI(TAG, "Unhandled AttributeId ID: '0x%04x", attributeId)); + VerifyOrExit(endpointId == 1 || endpointId == 2, ESP_LOGE(TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId)); + if (endpointId == 1) + { + uint8_t hue, saturation; + if (attributeId == ZCL_COLOR_CONTROL_CURRENT_HUE_ATTRIBUTE_ID) + { + hue = *value; + emberAfReadServerAttribute(endpointId, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_SATURATION_ATTRIBUTE_ID, + &saturation, sizeof(uint8_t)); + } + else + { + saturation = *value; + emberAfReadServerAttribute(endpointId, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_HUE_ATTRIBUTE_ID, &hue, + sizeof(uint8_t)); + } + statusLED1.SetColor(hue, saturation); + } +exit: + return; +} +#endif + void IdentifyTimerHandler(Layer * systemLayer, void * appState, CHIP_ERROR error) { statusLED1.Animate(); diff --git a/examples/all-clusters-app/esp32/main/Kconfig.projbuild b/examples/all-clusters-app/esp32/main/Kconfig.projbuild index 487528fce73940..89911735fbf307 100644 --- a/examples/all-clusters-app/esp32/main/Kconfig.projbuild +++ b/examples/all-clusters-app/esp32/main/Kconfig.projbuild @@ -22,7 +22,8 @@ menu "Demo" choice prompt "Device Type" - default DEVICE_TYPE_ESP32_DEVKITC + default DEVICE_TYPE_ESP32_DEVKITC if IDF_TARGET_ESP32 + default DEVICE_TYPE_ESP32_C3_DEVKITM if IDF_TARGET_ESP32C3 help Specifies the type of ESP32 device. diff --git a/examples/all-clusters-app/esp32/main/LEDWidget.cpp b/examples/all-clusters-app/esp32/main/LEDWidget.cpp index c6a5a8c5986510..13dcdc4893c2cf 100644 --- a/examples/all-clusters-app/esp32/main/LEDWidget.cpp +++ b/examples/all-clusters-app/esp32/main/LEDWidget.cpp @@ -27,12 +27,19 @@ #include "ScreenManager.h" -#include "driver/ledc.h" #include "esp_log.h" #include "esp_system.h" #include "esp_timer.h" +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM +#include "driver/rmt.h" +#include "led_strip.h" +#define RMT_TX_DEFAULT_GPIO GPIO_NUM_8 +#define RMT_TX_DEFAULT_CHANNEL RMT_CHANNEL_0 +static led_strip_t * strip = NULL; +#else +#include "driver/ledc.h" #include "hal/ledc_types.h" - +#endif void LEDWidget::Init(gpio_num_t gpioNum) { mLastChangeTimeUS = 0; @@ -44,7 +51,20 @@ void LEDWidget::Init(gpio_num_t gpioNum) mState = false; mError = false; errorTimer = NULL; - +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + if (gpioNum == RMT_TX_DEFAULT_GPIO) + { + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(RMT_TX_DEFAULT_GPIO, RMT_TX_DEFAULT_CHANNEL); + config.clk_div = 2; + rmt_config(&config); + rmt_driver_install(config.channel, 0, 0); + led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(1, (led_strip_dev_t) config.channel); + strip = led_strip_new_rmt_ws2812(&strip_config); + mDefaultOnBrightness = UINT8_MAX; + mHue = 0; + mSaturation = 0; + } +#else if (gpioNum < GPIO_NUM_MAX) { ledc_timer_config_t ledc_timer = { @@ -67,6 +87,7 @@ void LEDWidget::Init(gpio_num_t gpioNum) ledc_channel_config(&ledc_channel); mDefaultOnBrightness = UINT8_MAX; } +#endif } void LEDWidget::Set(bool state) @@ -77,11 +98,21 @@ void LEDWidget::Set(bool state) void LEDWidget::SetBrightness(uint8_t brightness) { +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + if (strip) + { + uint8_t red, green, blue; + HSB2rgb(mHue, mSaturation, brightness, red, green, blue); + strip->set_pixel(strip, 0, red, green, blue); + strip->refresh(strip, 100); + } +#else if (mGPIONum < GPIO_NUM_MAX) { ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, brightness); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); } +#endif if (brightness > 0) { mDefaultOnBrightness = brightness; @@ -155,11 +186,22 @@ void LEDWidget::DoSet(bool state) { bool stateChange = (mState != state); mState = state; +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + if (strip) + { + uint8_t red, green, blue; + uint8_t brightness = state ? mDefaultOnBrightness : 0; + HSB2rgb(mHue, mSaturation, brightness, red, green, blue); + strip->set_pixel(strip, 0, red, green, blue); + strip->refresh(strip, 100); + } +#else if (mGPIONum < GPIO_NUM_MAX) { ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, state ? mDefaultOnBrightness : 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); } +#endif if (stateChange) { #if CONFIG_HAVE_DISPLAY @@ -186,3 +228,60 @@ void LEDWidget::SetVLED(int id1, int id2) } } #endif + +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM +void LEDWidget::SetColor(uint8_t Hue, uint8_t Saturation) +{ + uint8_t red, green, blue; + uint8_t brightness = mState ? mDefaultOnBrightness : 0; + mHue = static_cast(Hue) * 360 / 254; // mHue [0, 360] + mSaturation = static_cast(Saturation) * 100 / 254; // mSaturation [0 , 100] + + HSB2rgb(mHue, mSaturation, brightness, red, green, blue); + strip->set_pixel(strip, 0, red, green, blue); + strip->refresh(strip, 100); +} + +void LEDWidget::HSB2rgb(uint16_t Hue, uint8_t Saturation, uint8_t brightness, uint8_t & red, uint8_t & green, uint8_t & blue) +{ + uint16_t i = Hue / 60; + uint16_t rgb_max = brightness; + uint16_t rgb_min = rgb_max * (100 - Saturation) / 100; + uint16_t diff = Hue % 60; + uint16_t rgb_adj = (rgb_max - rgb_min) * diff / 60; + + switch (i) + { + case 0: + red = rgb_max; + green = rgb_min + rgb_adj; + blue = rgb_min; + break; + case 1: + red = rgb_max - rgb_adj; + green = rgb_max; + blue = rgb_min; + break; + case 2: + red = rgb_min; + green = rgb_max; + blue = rgb_min + rgb_adj; + break; + case 3: + red = rgb_min; + green = rgb_max - rgb_adj; + blue = rgb_max; + break; + case 4: + red = rgb_min + rgb_adj; + green = rgb_min; + blue = rgb_max; + break; + default: + red = rgb_max; + green = rgb_min; + blue = rgb_max - rgb_adj; + break; + } +} +#endif diff --git a/examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h b/examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h index e68b61a018d077..7917c79cc80308 100644 --- a/examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h +++ b/examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h @@ -42,6 +42,9 @@ class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks void OnSessionEstablished(const chip::DeviceLayer::ChipDeviceEvent * event); void OnOnOffPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); void OnLevelControlAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + void OnColorControlAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); +#endif void OnIdentifyPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); bool mEndpointOnOffState[2]; diff --git a/examples/all-clusters-app/esp32/main/include/LEDWidget.h b/examples/all-clusters-app/esp32/main/include/LEDWidget.h index a3f6f6c9c4ed08..f90b0d76332b7c 100644 --- a/examples/all-clusters-app/esp32/main/include/LEDWidget.h +++ b/examples/all-clusters-app/esp32/main/include/LEDWidget.h @@ -45,7 +45,11 @@ class LEDWidget void BlinkOnError(); void Animate(); +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + void SetColor(uint8_t Hue, uint8_t Saturation); + void HSB2rgb(uint16_t Hue, uint8_t Saturation, uint8_t brightness, uint8_t & red, uint8_t & green, uint8_t & blue); +#endif #if CONFIG_HAVE_DISPLAY void SetVLED(int id1, int id2); #endif @@ -55,6 +59,10 @@ class LEDWidget uint32_t mBlinkOnTimeMS; uint32_t mBlinkOffTimeMS; uint8_t mDefaultOnBrightness; +#if CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM + uint16_t mHue; // mHue [0, 360] + uint8_t mSaturation; // mSaturation [0, 100] +#endif gpio_num_t mGPIONum; int mVLED1; int mVLED2; diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 6de0390eaa204b..dbe0a53e8028b2 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -87,7 +87,7 @@ using namespace ::chip::DeviceLayer; #elif CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM -#define STATUS_LED_GPIO_NUM GPIO_NUM_2 +#define STATUS_LED_GPIO_NUM GPIO_NUM_8 #else // !CONFIG_DEVICE_TYPE_ESP32_DEVKITC