Answers checklist.
IDF / ESP32-Arduino version.
ESP-IDF v5.5.4
Operating System used.
Linux
How did you build your project?
Command line with idf.py
Development Kit.
Custom board ESP32-Wroom-32
What is the expected behavior?
My node consists of several separate devices (a switch, addressable LEDs, and a few sensors). Everything operates correctly when controlled via the ESP-RainMaker cloud, and it should work just as well with local control via Matter. When I toggle the standalone switch, only that switch should activate, without affecting the lighting. Conversely, when I toggle the lighting switch, only the lighting should turn on, without affecting the standalone switch. In other words, commands from the ESP-RainMaker app need to be routed to distinct endpoints for the different devices.
What is the actual behavior?
Currently, cloud-based control via ESP-RainMaker works correctly; however, with local control via Matter, all commands from the ESP-RainMaker app are sent only to Endpoint 1. Endpoint 1 is currently configured for the addressable LEDs. When I turn on the LEDs, only the LEDs (Endpoint 1) activate. When I turn on the separate switch (Endpoint 2), the LEDs (Endpoint 1) activate instead. The same behavior occurs when turning them off. When I open the sensor readings page in the ESP-RainMaker app, the reading clusters for the endpoint are unrecognized. All devices are displayed using the name of Endpoint 1 (the LEDs).
Steps to reproduce.
-
In app_main:
light_handle = app_driver_light_init();
app_driver_handle_t button_handle = app_driver_button_init(light_handle);
switch_handle = app_driver_button_init(switch_handle);
app_driver_switch_set_power(switch_handle, DEFAULT_SWITCH_POWER);
button_driver_handle_t sbutton_handle = app_driver_button_init(switch_handle);
//app_reset_button_register((button_handle_t)switch_handle, WIFI_RESET_BUTTON_TIMEOUT, FACTORY_RESET_BUTTON_TIMEOUT);
temperature_sensor_handle = app_sensor_init();
-
In app_driver:
app_driver_handle_t app_driver_light_init()
{
/* Initialize led */
led_driver_config_t config = led_driver_get_config();
led_driver_handle_t handle = led_driver_init(&config);
return (app_driver_handle_t)handle;
}
app_driver_handle_t app_driver_button_init(void *user_data)
{
button_handle_t shandle = NULL;
const button_config_t btn_cfg = {0};
const button_gpio_config_t btn_gpio_cfg = {
.gpio_num = OUTPUT_GPIO2,
.active_level = 0,
};
if (iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &shandle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to create button device");
return NULL;
}
button_gpio_config_t gpio_cfg = {
.gpio_num = OUTPUT_GPIO2,
.active_level = 0,
.enable_power_save = false,
};
/* Configure power */
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
};
io_conf.pin_bit_mask = ((uint64_t)1 << OUTPUT_GPIO);
/* Configure the GPIO */
gpio_config(&io_conf);
iot_button_register_cb(shandle, BUTTON_SINGLE_CLICK, NULL, app_driver_button_toggle_cb, user_data);
return (button_driver_handle_t)shandle;
}
-
In app_matter_light
esp_err_t app_attribute_update_cb(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)
{
esp_err_t err = ESP_OK;
printf("AttrCB Endpoint ID: %d", endpoint_id);
//printf("AttrUpdate CB Light Endpoint ID: %d", light_endpoint_id);
if (type == PRE_UPDATE) {
/ Driver update */
if (endpoint_id == 1) {
led_driver_handle_t handle = (led_driver_handle_t)priv_data;
printf("AttrUpdate CB Light Endpoint ID: %d", light_endpoint_id);
if (cluster_id == OnOff::Id) {
if (attribute_id == OnOff::Attributes::OnOff::Id) {
err = app_driver_light_set_power(handle, val->val.b);
}
} else if (cluster_id == LevelControl::Id) {
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
err = app_driver_light_set_brightness(handle, REMAP_TO_RANGE(val->val.u8, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS));
}
} else if (cluster_id == ColorControl::Id) {
if (attribute_id == ColorControl::Attributes::CurrentHue::Id) {
err = app_driver_light_set_hue(handle, REMAP_TO_RANGE(val->val.u8, MATTER_HUE, STANDARD_HUE));
} else if (attribute_id == ColorControl::Attributes::CurrentSaturation::Id) {
int value=val->val.u8;
if(value>255) value=255;
if(value==0) value=255;
err = app_driver_light_set_saturation(handle, REMAP_TO_RANGE(value, MATTER_SATURATION, STANDARD_SATURATION));
printf("app_attribute_update_cb: %.2d", value);
} else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
//err = led_driver_set_temperature(handle, REMAP_TO_RANGE_INVERSE(val->val.u16, STANDARD_TEMPERATURE_FACTOR));
}
}
}
if (endpoint_id == 2) {
led_driver_handle_t handle = (led_driver_handle_t)priv_data;
if (cluster_id == OnOff::Id) {
printf("AttrCB Endpoint ID: %d", endpoint_id);
if (attribute_id == OnOff::Attributes::OnOff::Id) {
err = app_driver_switch_set_power(handle, val->val.b);
}
}
}
} else if (type == POST_UPDATE) {
if (!rmaker_init_done) {
ESP_LOGI(TAG, "RainMaker init not done. Not processing attribute update");
return ESP_OK;
}
if (endpoint_id == light_endpoint_id) {
/* RainMaker update */
const char *device_name = LIGHT_DEVICE_NAME;
const char *param_name = app_matter_get_rmaker_param_name_from_id(cluster_id, attribute_id);
if (!param_name) {
ESP_LOGD(TAG, "param name not handled");
return ESP_FAIL;
}
const esp_rmaker_node_t *node = esp_rmaker_get_node();
esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(node, device_name);
esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name);
if (!param) {
ESP_LOGE(TAG, "Param %s not found", param_name);
return ESP_FAIL;
}
esp_rmaker_param_val_t rmaker_val = app_matter_get_rmaker_val(val, cluster_id, attribute_id);
return esp_rmaker_param_update_and_report(param, rmaker_val);
}
if (endpoint_id == switch_endpoint_id) {
/* RainMaker update */
const char *device_name = SWITCH_DEVICE_NAME;
const char *param_name = app_matter_get_rmaker_param_name_from_id(cluster_id, attribute_id);
if (!param_name) {
ESP_LOGD(TAG, "param name not handled");
return ESP_FAIL;
}
printf("AttrCB Switch Endpoint ID: %d", endpoint_id);
const esp_rmaker_node_t *node = esp_rmaker_get_node();
esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(node, device_name);
esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name);
if (!param) {
ESP_LOGE(TAG, "Param %s not found", param_name);
return ESP_FAIL;
}
esp_rmaker_param_val_t rmaker_val = app_matter_get_rmaker_val(val, cluster_id, attribute_id);
return esp_rmaker_param_update_and_report(param, rmaker_val);
}
}
return err;
}
esp_err_t app_matter_switch_create(button_driver_handle_t driver_handle)
{
node_t *node = node::get();
if (!node) {
ESP_LOGE(TAG, "Matter node not found");
return ESP_FAIL;
}
on_off_light_switch::config_t switch_config;
endpoint_t *endpoint = on_off_light_switch::create(node, &switch_config, ENDPOINT_FLAG_NONE, driver_handle);
printf("Switch Endpoint ID: %d", switch_endpoint_id);
if (!endpoint) {
ESP_LOGE(TAG, "Matter endpoint creation failed");
return ESP_FAIL;
}
cluster::groups::config_t groups_config;
cluster::groups::create(endpoint, &groups_config, CLUSTER_FLAG_SERVER | CLUSTER_FLAG_CLIENT);
//switch_endpoint_id = endpoint::get_id(endpoint);
switch_endpoint_id = 2;
endpoint::enable(endpoint);
printf("Switch Endpoint ID: %d", switch_endpoint_id);
ESP_LOGI(TAG, "Switch created with endpoint_id %d", switch_endpoint_id);
return ESP_OK;
}
esp_err_t app_matter_sensor_create(app_driver_handle_t driver_handle)
{
node_t *node = node::get();
if (!node) {
ESP_LOGE(TAG, "Matter node not found");
return ESP_FAIL;
}
temperature_sensor::config_t temp_sensor_config;
endpoint_t *temp_sensor_ep = temperature_sensor::create(node, &temp_sensor_config, ENDPOINT_FLAG_NONE, driver_handle);
temp_endpoint_id = endpoint::get_id(temp_sensor_ep);
//cluster_t *temp_cluster = cluster::get(temp_sensor_ep, TemperatureMeasurement::Id);
endpoint::enable(temp_sensor_ep);
temperature_measurement::config_t temperature_measurement_config;
temp_sensor_config.temperature_measurement.measured_value = 2500; // 25.00 °C по умолчанию
cluster_t *cluster = temperature_measurement::create(temp_sensor_ep, &temperature_measurement_config, CLUSTER_FLAG_SERVER);
ABORT_APP_ON_FAILURE(temp_sensor_ep != nullptr, ESP_LOGE(TAG, "Failed to create temperature_sensor endpoint"));
printf("Sensor Endpoint ID: %d", temp_endpoint_id);
//{
// esp_matter_attr_val_t temp_val;
//}
// add the humidity sensor device
humidity_sensor::config_t humidity_sensor_config;
endpoint_t * humidity_sensor_ep = humidity_sensor::create(node, &humidity_sensor_config, ENDPOINT_FLAG_NONE, driver_handle);
ABORT_APP_ON_FAILURE(humidity_sensor_ep != nullptr, ESP_LOGE(TAG, "Failed to create humidity_sensor endpoint"));
endpoint::enable(humidity_sensor_ep);
// initialize temperature and humidity sensor driver (shtc3)
static bme_sensor_config_t bme_config = {
.temperature = {
.cb = temp_sensor_notification,
.endpoint_id = endpoint::get_id(temp_sensor_ep),
},
.humidity = {
.cb = humidity_sensor_notification,
.endpoint_id = endpoint::get_id(humidity_sensor_ep),
},
};
//esp_rmaker_param_val_t rmaker_val = app_matter_get_rmaker_val(val, cluster_id, attribute_id);
// return esp_rmaker_param_update_and_report(param, rmaker_val);
//err = bme_sensor_init(&bme_config);
return ESP_OK;
}
Debug Logs.
Endpoints created
I (994) app_matter: Light created with endpoint_id 1
Light Endpoint ID: 1 Switch Endpoint ID: 0 Switch Endpoint ID: 2I (1004) app_matter: Switch created with endpoint_id 2
Sensor Endpoint ID: 3
Consoles log when open sensors page in mobile app:
E (23164) chip[DMG]: Read request on unknown cluster - no data version available
E (23164) chip[DMG]: Fail to retrieve data, roll back and encode status on clusterId: 0x0000_0402, attributeId: 0x0000_0000err = 5c3
More Information.

Answers checklist.
IDF / ESP32-Arduino version.
ESP-IDF v5.5.4
Operating System used.
Linux
How did you build your project?
Command line with idf.py
Development Kit.
Custom board ESP32-Wroom-32
What is the expected behavior?
My node consists of several separate devices (a switch, addressable LEDs, and a few sensors). Everything operates correctly when controlled via the ESP-RainMaker cloud, and it should work just as well with local control via Matter. When I toggle the standalone switch, only that switch should activate, without affecting the lighting. Conversely, when I toggle the lighting switch, only the lighting should turn on, without affecting the standalone switch. In other words, commands from the ESP-RainMaker app need to be routed to distinct endpoints for the different devices.
What is the actual behavior?
Currently, cloud-based control via ESP-RainMaker works correctly; however, with local control via Matter, all commands from the ESP-RainMaker app are sent only to Endpoint 1. Endpoint 1 is currently configured for the addressable LEDs. When I turn on the LEDs, only the LEDs (Endpoint 1) activate. When I turn on the separate switch (Endpoint 2), the LEDs (Endpoint 1) activate instead. The same behavior occurs when turning them off. When I open the sensor readings page in the ESP-RainMaker app, the reading clusters for the endpoint are unrecognized. All devices are displayed using the name of Endpoint 1 (the LEDs).
Steps to reproduce.
In app_main:
light_handle = app_driver_light_init();
app_driver_handle_t button_handle = app_driver_button_init(light_handle);
switch_handle = app_driver_button_init(switch_handle);
app_driver_switch_set_power(switch_handle, DEFAULT_SWITCH_POWER);
button_driver_handle_t sbutton_handle = app_driver_button_init(switch_handle);
//app_reset_button_register((button_handle_t)switch_handle, WIFI_RESET_BUTTON_TIMEOUT, FACTORY_RESET_BUTTON_TIMEOUT);
temperature_sensor_handle = app_sensor_init();
In app_driver:
app_driver_handle_t app_driver_light_init()
{
/* Initialize led */
led_driver_config_t config = led_driver_get_config();
led_driver_handle_t handle = led_driver_init(&config);
return (app_driver_handle_t)handle;
}
app_driver_handle_t app_driver_button_init(void *user_data)
{
button_handle_t shandle = NULL;
const button_config_t btn_cfg = {0};
const button_gpio_config_t btn_gpio_cfg = {
.gpio_num = OUTPUT_GPIO2,
.active_level = 0,
};
if (iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &shandle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to create button device");
return NULL;
}
}
In app_matter_light
esp_err_t app_attribute_update_cb(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)
{
esp_err_t err = ESP_OK;
printf("AttrCB Endpoint ID: %d", endpoint_id);
//printf("AttrUpdate CB Light Endpoint ID: %d", light_endpoint_id);
if (type == PRE_UPDATE) {
/ Driver update */
if (endpoint_id == 1) {
led_driver_handle_t handle = (led_driver_handle_t)priv_data;
printf("AttrUpdate CB Light Endpoint ID: %d", light_endpoint_id);
if (cluster_id == OnOff::Id) {
if (attribute_id == OnOff::Attributes::OnOff::Id) {
err = app_driver_light_set_power(handle, val->val.b);
}
} else if (cluster_id == LevelControl::Id) {
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
err = app_driver_light_set_brightness(handle, REMAP_TO_RANGE(val->val.u8, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS));
}
} else if (cluster_id == ColorControl::Id) {
if (attribute_id == ColorControl::Attributes::CurrentHue::Id) {
err = app_driver_light_set_hue(handle, REMAP_TO_RANGE(val->val.u8, MATTER_HUE, STANDARD_HUE));
} else if (attribute_id == ColorControl::Attributes::CurrentSaturation::Id) {
int value=val->val.u8;
if(value>255) value=255;
if(value==0) value=255;
err = app_driver_light_set_saturation(handle, REMAP_TO_RANGE(value, MATTER_SATURATION, STANDARD_SATURATION));
printf("app_attribute_update_cb: %.2d", value);
} else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
//err = led_driver_set_temperature(handle, REMAP_TO_RANGE_INVERSE(val->val.u16, STANDARD_TEMPERATURE_FACTOR));
}
}
}
} else if (type == POST_UPDATE) {
if (!rmaker_init_done) {
ESP_LOGI(TAG, "RainMaker init not done. Not processing attribute update");
return ESP_OK;
}
if (endpoint_id == light_endpoint_id) {
/* RainMaker update */
const char *device_name = LIGHT_DEVICE_NAME;
const char *param_name = app_matter_get_rmaker_param_name_from_id(cluster_id, attribute_id);
if (!param_name) {
ESP_LOGD(TAG, "param name not handled");
return ESP_FAIL;
}
}
if (endpoint_id == switch_endpoint_id) {
/* RainMaker update */
const char *device_name = SWITCH_DEVICE_NAME;
const char *param_name = app_matter_get_rmaker_param_name_from_id(cluster_id, attribute_id);
if (!param_name) {
ESP_LOGD(TAG, "param name not handled");
return ESP_FAIL;
}
printf("AttrCB Switch Endpoint ID: %d", endpoint_id);
const esp_rmaker_node_t *node = esp_rmaker_get_node();
esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(node, device_name);
esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name);
if (!param) {
ESP_LOGE(TAG, "Param %s not found", param_name);
return ESP_FAIL;
}
}
}
return err;
}
esp_err_t app_matter_switch_create(button_driver_handle_t driver_handle)
{
node_t *node = node::get();
if (!node) {
ESP_LOGE(TAG, "Matter node not found");
return ESP_FAIL;
}
}
esp_err_t app_matter_sensor_create(app_driver_handle_t driver_handle)
{
node_t *node = node::get();
if (!node) {
ESP_LOGE(TAG, "Matter node not found");
return ESP_FAIL;
}
temperature_sensor::config_t temp_sensor_config;
endpoint::enable(humidity_sensor_ep);
// initialize temperature and humidity sensor driver (shtc3)
return ESP_OK;
}
Debug Logs.
More Information.