Issue with LED Color Mode and Slow Response in ESP32-C3 with WS2812 using esp32-arduino-matter

Hello, everyone. I am currently trying to develop using esp32-arduino-matter. I am using an ESP32-C3 with WS2812 LEDs, and I have already implemented the extended_color_light. However, after adding it to Apple Home, the light turns into a Color Temperature Light. I am also encountering a slow LED response during Pre Update. I would appreciate it if anyone could help me identify what the issue might be. Thank you!

#include <Adafruit_NeoPixel.h>
#include "Matter.h"
#include <esp_matter.h>
#include <app/server/OnboardingCodesUtil.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include "func.h"

using namespace chip;
using namespace chip::app::Clusters;
using namespace esp_matter;
using namespace esp_matter::endpoint;

#define REMAP_TO_RANGE(value, from, to) ((value * to) / from)  // Mapping value to a different range
#define REMAP_TO_RANGE_INVERSE(value, factor) (factor / (value ? value : 1))  // Inverse mapping of value

static int hue = 0;         // Hue (0-360 degrees)
static int saturation = 0;  // Saturation (0-255)
static int brightness = 0;  // Brightness (assuming default value)

const int LED_PIN = 1;  // Pin where the LED is connected

// Cluster and attribute IDs used by Matter light device
const uint32_t CLUSTER_ID = OnOff::Id, CID_LevelCtl = LevelControl::Id, CID_ColorCtl = ColorControl::Id;
const uint32_t ATTRIBUTE_ID = OnOff::Attributes::OnOff::Id, AID_LevelCtl = LevelControl::Attributes::CurrentLevel::Id,
               AID_ColorCtlHue = ColorControl::Attributes::CurrentHue::Id, AID_ColorCtlSat = ColorControl::Attributes::CurrentSaturation::Id, AID_ColorCtlCol = ColorControl::Attributes::ColorTemperatureMireds::Id;

// Endpoint and attribute ref that will be assigned to Matter device
uint16_t light_endpoint_id = 0;  // This is the endpoint ID for the light device

#define NUMPIXELS 1  // Number of pixels (LEDs) used
Adafruit_NeoPixel pixels(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);  // Initialize the LED strip

// Callback function for device events
static void on_device_event(const ChipDeviceEvent *event, intptr_t arg) {}

// Callback for device identification, for example, during the commissioning process
static esp_err_t on_identification(identification::callback_type_t type, uint16_t endpoint_id,
                                   uint8_t effect_id, uint8_t effect_variant, void *priv_data) {
  return ESP_OK;  // Return success when the device is identified
}

// Listener for attribute update requests. This function is triggered when an attribute is updated in Matter.
static esp_err_t on_attribute_update(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id,
                                     uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) {

  // Handle On/Off attribute update (for turning the light on/off)
  if (type == attribute::PRE_UPDATE && endpoint_id == light_endpoint_id && cluster_id == CLUSTER_ID && attribute_id == ATTRIBUTE_ID) {
    bool new_state = val->val.b;  // Get the new On/Off state
    if (new_state) {
      // Turn on the light and set it to white
      pixels.setBrightness(brightness);
      pixels.show();
    } else {
      // Turn off the light
      pixels.setBrightness(0);
      pixels.show();
    }
  }

  // Handle LevelControl attribute update (for adjusting brightness)
  if (type == attribute::PRE_UPDATE && endpoint_id == light_endpoint_id && cluster_id == CID_LevelCtl && attribute_id == AID_LevelCtl) {
    brightness = REMAP_TO_RANGE(val->val.u8, 254, 255);  // Map the brightness value
    pixels.setBrightness(brightness);  // Set the new brightness
  }

  // Handle ColorControl attribute update (for changing color)
  if (type == attribute::PRE_UPDATE && endpoint_id == light_endpoint_id && cluster_id == CID_ColorCtl) {
    if (attribute_id == AID_ColorCtlHue) {
      hue = REMAP_TO_RANGE(val->val.u8, 254, 360);  // Map the hue value to 360 degrees
      ESP_LOGI("ColorControl", "Hue updated: %d", hue);
    } else if (attribute_id == AID_ColorCtlSat) {
      saturation = REMAP_TO_RANGE(val->val.u8, 254, 255);  // Map the saturation value
      ESP_LOGI("ColorControl", "Saturation updated: %d", saturation);
    }

    // Update light display when Hue or Saturation is updated
    if (attribute_id == AID_ColorCtlHue || attribute_id == AID_ColorCtlSat) {
      uint8_t r, g, b;
      hsv_to_rgb(hue, saturation, brightness, r, g, b);  // Convert HSV to RGB
      pixels.setPixelColor(0, pixels.Color(r, g, b));  // Set the LED color
      pixels.show();
      ESP_LOGI("ColorControl", "Updated RGB from HSV(%d, %d, %d) -> RGB(%d, %d, %d)", hue, saturation, brightness, r, g, b);
    } else if (attribute_id == AID_ColorCtlCol) {
      // Handle color temperature change
      uint32_t kelvin = mireds_to_kelvin(val->val.u16);  // Convert Mireds to Kelvin
      uint8_t r, g, b;
      kelvin_to_rgb(kelvin, r, g, b);  // Convert Kelvin to RGB
      pixels.setPixelColor(0, pixels.Color(r, g, b));  // Set the LED color
      pixels.show();
      ESP_LOGI("ColorControl", "Color Temperature: %d Mireds (%d K) -> RGB(%d, %d, %d)",
               val->val.u16, kelvin, r, g, b);
    }
  }
  return ESP_OK;  // Return success after processing attribute update
}

void setup() {
  Serial.begin(115200);  // Initialize the serial communication

  pixels.begin();  // Initialize the LED strip
  esp_log_level_set("*", ESP_LOG_DEBUG);  // Enable debug logging

  // Setup Matter node
  node::config_t node_config;
  node_t *node = node::create(&node_config, on_attribute_update, on_identification);  // Create Matter node

  // Set up initial light configuration (off by default)
  extended_color_light::config_t light_config;
  light_config.on_off.on_off = false;  // Light is initially off
  light_config.on_off.lighting.start_up_on_off = nullptr;
  light_config.level_control.current_level = 64;  // Set default brightness level
  light_config.level_control.on_level = 64;
  light_config.level_control.lighting.start_up_current_level = 64;
  light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::EMBER_ZCL_COLOR_MODE_COLOR_TEMPERATURE;
  light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::EMBER_ZCL_COLOR_MODE_COLOR_TEMPERATURE;

  endpoint_t *endpoint = extended_color_light::create(node, &light_config, ENDPOINT_FLAG_NONE, NULL);  // Create light endpoint

  // Save the generated endpoint ID
  light_endpoint_id = endpoint::get_id(endpoint);

  // Set custom Device Attestation Credentials (DAC) provider
  esp_matter::set_custom_dac_provider(chip::Credentials::Examples::GetExampleDACProvider());

  // Start the Matter device
  esp_matter::start(on_device_event);

  // Print the onboarding codes needed for Matter device setup
  PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE));
}

void loop() {
  // The loop is intentionally left empty, as the device is event-driven
}

func.h

// Function to convert HSV to RGB
void hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v, uint8_t &r, uint8_t &g, uint8_t &b) {
    float hh = h / 60.0;
    int i = floor(hh);
    float ff = hh - i;
    float p = v * (1.0 - s / 255.0);
    float q = v * (1.0 - (s / 255.0) * ff);
    float t = v * (1.0 - (s / 255.0) * (1.0 - ff));

    // Switch case to calculate RGB values based on HSV
    switch (i) {
        case 0: r = v; g = t; b = p; break;
        case 1: r = q; g = v; b = p; break;
        case 2: r = p; g = v; b = t; break;
        case 3: r = p; g = q; b = v; break;
        case 4: r = t; g = p; b = v; break;
        case 5:
        default: r = v; g = p; b = q; break;
    }
}

// Function to convert Mireds to Kelvin
uint32_t mireds_to_kelvin(uint16_t mireds) {
    return 1000000 / mireds;  // Return the Kelvin temperature from Mireds
}

// Function to convert Kelvin to RGB
void kelvin_to_rgb(uint32_t kelvin, uint8_t &r, uint8_t &g, uint8_t &b) {
    float temperature = kelvin / 100.0;  // Convert Kelvin to temperature in Celsius

    // Calculate the Red (R) value
    if (temperature <= 66) {
        r = 255;
    } else {
        r = temperature - 60;
        r = 329.698727446 * pow(r, -0.1332047592);  // Apply formula for red color
        r = (r < 0) ? 0 : (r > 255) ? 255 : r;  // Clamp value between 0 and 255
    }

    // Calculate the Green (G) value
    if (temperature <= 66) {
        g = temperature;
        g = 99.4708025861 * log(g) - 161.1195681661;  // Apply formula for green color
        g = (g < 0) ? 0 : (g > 255) ? 255 : g;  // Clamp value between 0 and 255
    } else {
        g = temperature - 60;
        g = 288.1221695283 * pow(g, -0.0755148492);  // Apply formula for green color
        g = (g < 0) ? 0 : (g > 255) ? 255 : g;  // Clamp value between 0 and 255
    }

    // Calculate the Blue (B) value
    if (temperature >= 66) {
        b = 255;
    } else {
        if (temperature <= 19) {
            b = 0;
        } else {
            b = temperature - 10;
            b = 138.5177312231 * log(b) - 305.0447927307;  // Apply formula for blue color
            b = (b < 0) ? 0 : (b > 255) ? 255 : b;  // Clamp value between 0 and 255
        }
    }
}

I moved your topic to a more appropriate forum category @louiekuo0313 .

The Nano ESP32 category you chose is only used for discussions directly related to the Arduino Nano ESP32 board.

In the future, please take the time to pick the forum category that best suits the subject of your question. There is an "About the _____ category" topic at the top of each category that explains its purpose.

Thanks in advance for your cooperation.

I don't appear to be able to find where you moved this topic - can you identify the forum category to which you moved it please?

@ValorousOne1 you can see which category the topic is in by simply scrolling up to the top of the topic page and looking at the line below the title:

Oh, I understand now - I'm actually reading the "moved" topic - not the "original" one! I guess I misinterpreted "moved" to mean the topic would be copied to a new category but the original retained with the "move" notice. Silly me - of course moved means just that, not copied.

I think you do understand now, but this is incorrect. The "moved" topic and the "original" topic are one and the same. The topic was simply moved to a different forum category.

So you are indeed reading the "original" topic.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.