We are trying to add CarbonDioxideConcentration cluster in matter. we are able to add temperature and humidity clusters and values which are updated are getting read in chip tool properly.
From the post (https://devzone.nordicsemi.com/f/nordic-q-a/111148/matter-setting-carbondioxideconcentrationmeasurement-value) got to know that to set value for CarboDiaxide it needs to follow the sample example https://github.com/nrfconnect/sdk-connectedhomeip/blob/ca3672fbb939180da8e43e6994e01c89fa9dcd02/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp#L20
we implemented similar way but when try to read values in chip tool for CarbonDioxideConcentration it still fails.
Command have Used : chip-tool carbondioxideconcentrationmeasurement read measured-value 1110111100001110 2
Error : ( [TOO] Run command failure: IM Error 0x00000501: General error: 0x01 (FAILURE) )
Any Hints or support will be appreciated to get it working
Have attached the code to add Temperature, Humidity and CarbonDioxideConcentration clusters in Light Bulb sample. The changes which are done for getting CarbonDioxideConcentration
values are as below
app_task.h
app_task.cpp
app_task.h file
app_task.h /* * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include "board/board.h" #include "pwm/pwm_device.h" #include <app/clusters/concentration-measurement-server/concentration-measurement-server.h> #include <platform/CHIPDeviceLayer.h> #include <app-common/zap-generated/attributes/Accessors.h> #include <app-common/zap-generated/cluster-objects.h> #pragma once struct k_timer; struct Identify; enum class LightingActor : uint8_t { Remote, Button }; struct LightingEvent { uint8_t Action; LightingActor Actor; }; class AppTask { public: static AppTask &Instance() { static AppTask sAppTask; return sAppTask; }; CHIP_ERROR StartApp(); void UpdateClusterState(); void InitPWMDDevice(); Nrf::PWMDevice &GetPWMDevice() { return mPWMDevice; } static void IdentifyStartHandler(Identify *); static void IdentifyStopHandler(Identify *); static void TriggerIdentifyEffectHandler(Identify *); static void TriggerEffectTimerTimeoutCallback(k_timer *timer); // pj // void StartSensorTimer(); void StartSensorTimer(int time); static void StopSensorTimer(); static void SensorMeasureHandler(); static void SensorActivateHandler(); static void SensorDeactivateHandler(); // Constructor declaration AppTask(); private: CHIP_ERROR Init(); static void LightingActionEventHandler(const LightingEvent &event); static void ButtonEventHandler(Nrf::ButtonState state, Nrf::ButtonMask hasChanged); static void ActionInitiated(Nrf::PWMDevice::Action_t action, int32_t actor); static void ActionCompleted(Nrf::PWMDevice::Action_t action, int32_t actor); chip::app::Clusters::ConcentrationMeasurement::Instance<true, true, true, true, true, true> co2_cluster; bool mInitSuccess; #ifdef CONFIG_AWS_IOT_INTEGRATION static bool AWSIntegrationCallback(struct aws_iot_integration_cb_data *data); #endif Nrf::PWMDevice mPWMDevice; };
app_task.cpp
app_task.cpp /* * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include "app_task.h" #include <cstdlib> #include <cstdio> #include<stdio.h> #include <optional> #ifdef CONFIG_AWS_IOT_INTEGRATION #include "aws_iot_integration.h" #endif #include "app/matter_init.h" #include "app/task_executor.h" #if defined(CONFIG_PWM) #include "pwm/pwm_device.h" #endif #ifdef CONFIG_CHIP_OTA_REQUESTOR #include "dfu/ota/ota_util.h" #endif #include <app-common/zap-generated/attributes/Accessors.h> #include <app-common/zap-generated/cluster-objects.h> #include <app/DeferredAttributePersistenceProvider.h> #include <app/clusters/identify-server/identify-server.h> #include <app/server/OnboardingCodesUtil.h> #include <app/server/Server.h> #include <zephyr/logging/log.h> k_timer sSensorTimer; LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); using namespace ::chip; using namespace ::chip::app; using namespace ::chip::DeviceLayer; namespace { constexpr EndpointId kLightEndpointId = 1; constexpr EndpointId kAllSenEndpointId=2; constexpr EndpointId kSensorEndpointId=3; constexpr uint8_t kDefaultMinLevel = 0; constexpr uint8_t kDefaultMaxLevel = 254; constexpr uint16_t kTriggerEffectTimeout = 5000; constexpr uint16_t kTriggerEffectFinishTimeout = 1000; k_timer sTriggerEffectTimer; Identify sIdentify = { kLightEndpointId, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator, AppTask::TriggerIdentifyEffectHandler }; bool sIsTriggerEffectActive = false; #if defined(CONFIG_PWM) const struct pwm_dt_spec sLightPwmDevice = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led1)); #endif // Define a custom attribute persister which makes actual write of the CurrentLevel attribute value // to the non-volatile storage only when it has remained constant for 5 seconds. This is to reduce // the flash wearout when the attribute changes frequently as a result of MoveToLevel command. // DeferredAttribute object describes a deferred attribute, but also holds a buffer with a value to // be written, so it must live so long as the DeferredAttributePersistenceProvider object. DeferredAttribute gCurrentLevelPersister(ConcreteAttributePath(kLightEndpointId, Clusters::LevelControl::Id, Clusters::LevelControl::Attributes::CurrentLevel::Id)); DeferredAttributePersistenceProvider gDeferredAttributePersister(Server::GetInstance().GetDefaultAttributePersister(), Span<DeferredAttribute>(&gCurrentLevelPersister, 1), System::Clock::Milliseconds32(5000)); #define APPLICATION_BUTTON_MASK DK_BTN2_MSK } /* namespace */ void AppTask::IdentifyStartHandler(Identify *) { Nrf::PostTask( [] { Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Blink(Nrf::LedConsts::kIdentifyBlinkRate_ms); }); } void AppTask::IdentifyStopHandler(Identify *) { Nrf::PostTask([] { Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Set(false); #if defined(CONFIG_PWM) Instance().mPWMDevice.ApplyLevel(); #endif }); } void AppTask::TriggerEffectTimerTimeoutCallback(k_timer *timer) { LOG_INF("Identify effect completed"); sIsTriggerEffectActive = false; Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Set(false); #if defined(CONFIG_PWM) Instance().mPWMDevice.ApplyLevel(); #endif } void AppTask::TriggerIdentifyEffectHandler(Identify *identify) { switch (identify->mCurrentEffectIdentifier) { /* Just handle all effects in the same way. */ case Clusters::Identify::EffectIdentifierEnum::kBlink: case Clusters::Identify::EffectIdentifierEnum::kBreathe: case Clusters::Identify::EffectIdentifierEnum::kOkay: case Clusters::Identify::EffectIdentifierEnum::kChannelChange: LOG_INF("Identify effect identifier changed to %d", static_cast<uint8_t>(identify->mCurrentEffectIdentifier)); sIsTriggerEffectActive = false; k_timer_stop(&sTriggerEffectTimer); k_timer_start(&sTriggerEffectTimer, K_MSEC(kTriggerEffectTimeout), K_NO_WAIT); #if defined(CONFIG_PWM) Instance().mPWMDevice.SuppressOutput(); #endif Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Blink(Nrf::LedConsts::kIdentifyBlinkRate_ms); break; case Clusters::Identify::EffectIdentifierEnum::kFinishEffect: LOG_INF("Identify effect finish triggered"); k_timer_stop(&sTriggerEffectTimer); k_timer_start(&sTriggerEffectTimer, K_MSEC(kTriggerEffectFinishTimeout), K_NO_WAIT); break; case Clusters::Identify::EffectIdentifierEnum::kStopEffect: if (sIsTriggerEffectActive) { sIsTriggerEffectActive = false; k_timer_stop(&sTriggerEffectTimer); Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Set(false); #if defined(CONFIG_PWM) Instance().mPWMDevice.ApplyLevel(); #endif } break; default: LOG_ERR("Received invalid effect identifier."); break; } } void AppTask::LightingActionEventHandler(const LightingEvent &event) { #if defined(CONFIG_PWM) Nrf::PWMDevice::Action_t action = Nrf::PWMDevice::INVALID_ACTION; int32_t actor = 0; if (event.Actor == LightingActor::Button) { action = Instance().mPWMDevice.IsTurnedOn() ? Nrf::PWMDevice::OFF_ACTION : Nrf::PWMDevice::ON_ACTION; actor = static_cast<int32_t>(event.Actor); } if (action == Nrf::PWMDevice::INVALID_ACTION || !Instance().mPWMDevice.InitiateAction(action, actor, NULL)) { LOG_INF("An action could not be initiated."); } #else Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).Set(!Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).GetState()); #endif } void AppTask::ButtonEventHandler(Nrf::ButtonState state, Nrf::ButtonMask hasChanged) { if ((APPLICATION_BUTTON_MASK & hasChanged) & state) { Nrf::PostTask([] { LightingEvent event; event.Actor = LightingActor::Button; SensorActivateHandler(); LightingActionEventHandler(event); }); } } #ifdef CONFIG_AWS_IOT_INTEGRATION bool AppTask::AWSIntegrationCallback(struct aws_iot_integration_cb_data *data) { LOG_INF("Attribute change requested from AWS IoT: %d", data->value); Protocols::InteractionModel::Status status; VerifyOrDie(data->error == 0); if (data->attribute_id == ATTRIBUTE_ID_ONOFF) { /* write the new on/off value */ status = Clusters::OnOff::Attributes::OnOff::Set(kLightEndpointId, data->value); if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Updating on/off cluster failed: %x", to_underlying(status)); return false; } } else if (data->attribute_id == ATTRIBUTE_ID_LEVEL_CONTROL) { /* write the current level */ status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kLightEndpointId, data->value); if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Updating level cluster failed: %x", to_underlying(status)); return false; } } return true; } #endif /* CONFIG_AWS_IOT_INTEGRATION */ #if defined(CONFIG_PWM) void AppTask::ActionInitiated(Nrf::PWMDevice::Action_t action, int32_t actor) { if (action == Nrf::PWMDevice::ON_ACTION) { LOG_INF("Turn On Action has been initiated"); } else if (action == Nrf::PWMDevice::OFF_ACTION) { LOG_INF("Turn Off Action has been initiated"); } else if (action == Nrf::PWMDevice::LEVEL_ACTION) { LOG_INF("Level Action has been initiated"); } } void AppTask::ActionCompleted(Nrf::PWMDevice::Action_t action, int32_t actor) { if (action == Nrf::PWMDevice::ON_ACTION) { LOG_INF("Turn On Action has been completed"); } else if (action == Nrf::PWMDevice::OFF_ACTION) { LOG_INF("Turn Off Action has been completed"); } else if (action == Nrf::PWMDevice::LEVEL_ACTION) { LOG_INF("Level Action has been completed"); } if (actor == static_cast<int32_t>(LightingActor::Button)) { Instance().UpdateClusterState(); } } #endif /* CONFIG_PWM */ void AppTask::UpdateClusterState() { SystemLayer().ScheduleLambda([this] { #if defined(CONFIG_PWM) /* write the new on/off value */ Protocols::InteractionModel::Status status = Clusters::OnOff::Attributes::OnOff::Set(kLightEndpointId, mPWMDevice.IsTurnedOn()); #else Protocols::InteractionModel::Status status = Clusters::OnOff::Attributes::OnOff::Set( kLightEndpointId, Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).GetState()); #endif if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Updating on/off cluster failed: %x", to_underlying(status)); } #if defined(CONFIG_PWM) /* write the current level */ status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kLightEndpointId, mPWMDevice.GetLevel()); #else /* write the current level */ if (Nrf::GetBoard().GetLED(Nrf::DeviceLeds::LED2).GetState()) { status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kLightEndpointId, 100); } else { status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kLightEndpointId, 0); } #endif if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Updating level cluster failed: %x", to_underlying(status)); } }); } void AppTask::InitPWMDDevice() { #if defined(CONFIG_PWM) /* Initialize lighting device (PWM) */ uint8_t minLightLevel = kDefaultMinLevel; Clusters::LevelControl::Attributes::MinLevel::Get(kLightEndpointId, &minLightLevel); uint8_t maxLightLevel = kDefaultMaxLevel; Clusters::LevelControl::Attributes::MaxLevel::Get(kLightEndpointId, &maxLightLevel); Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::Type currentLevel; Clusters::LevelControl::Attributes::CurrentLevel::Get(kLightEndpointId, currentLevel); int ret = mPWMDevice.Init(&sLightPwmDevice, minLightLevel, maxLightLevel, currentLevel.ValueOr(kDefaultMaxLevel)); if (ret != 0) { LOG_ERR("Failed to initialize PWD device."); } mPWMDevice.SetCallbacks(ActionInitiated, ActionCompleted); #endif } //pj void AppTask::SensorActivateHandler() { AppTask::Instance().StartSensorTimer(5000);//StartSensorTimer(500); } void AppTask::SensorDeactivateHandler() { StopSensorTimer(); } AppTask::AppTask():co2_cluster(kAllSenEndpointId, chip::app::Clusters::CarbonDioxideConcentrationMeasurement::Id, chip::app::Clusters::ConcentrationMeasurement::MeasurementMediumEnum::kAir, chip::app::Clusters::ConcentrationMeasurement::MeasurementUnitEnum::kPpm) { // Initialize the CO2 cluster // co2_cluster.Init(); CHIP_ERROR initResult = co2_cluster.Init(); // Check if initialization not successful if (initResult != CHIP_NO_ERROR) { // Log the error LOG_ERR("Failed to initialize CO2 cluster, error code: "); // Set the initialization success flag to false mInitSuccess = false; } } void AppTask::SensorMeasureHandler() { printf("************ Temp value ************\n"); //kAllSenEndpointIdk int16_t temperature = int16_t(rand()%5000); printf("Sample Sensor Temperature : %d\n",temperature); chip::app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set( /* endpoint ID 2*/ kAllSenEndpointId, /* temperature in 0.01*C int16_t(rand() % 5000)*/temperature); int16_t humidity = int16_t(rand()%100); printf("Sample Sensor Humidity : %d\n",humidity); chip::app::Clusters::RelativeHumidityMeasurement::Attributes::MeasuredValue::Set( /* endpoint ID 3 */ kAllSenEndpointId, /* temperature in 0.01*C int16_t(rand() % 5000)*/humidity); float value = float(rand() % 5000); AppTask& appTask = AppTask::Instance(); appTask.co2_cluster.SetMeasuredValue(chip::app::DataModel::MakeNullable(2.0f)); //(chip::app::DataModel::Nullable<float>(value));//(value); LOG_INF("Sample Sensor CO2 : %f\n",value); // appTask.co2_cluster.SetMeasuredValue(DataModel::Nullable<float>(value)); } void SensorTimerHandler(k_timer *timer) { Nrf::PostTask([] { AppTask::SensorMeasureHandler(); }); } void AppTask::StartSensorTimer(int time) { k_timer_start(&sSensorTimer, K_MSEC(time), K_MSEC(time)); } void AppTask::StopSensorTimer() { k_timer_stop(&sSensorTimer); } CHIP_ERROR AppTask::Init() { /* Initialize Matter stack */ ReturnErrorOnFailure(Nrf::Matter::PrepareServer(Nrf::Matter::InitData{ .mPostServerInitClbk = [] { app::SetAttributePersistenceProvider(&gDeferredAttributePersister); return CHIP_NO_ERROR; } })); if (!Nrf::GetBoard().Init(ButtonEventHandler)) { LOG_ERR("User interface initialization failed."); return CHIP_ERROR_INCORRECT_STATE; } // co2_cluster(); /* Register Matter event handler that controls the connectivity status LED based on the captured Matter network * state. */ ReturnErrorOnFailure(Nrf::Matter::RegisterEventHandler(Nrf::Board::DefaultMatterEventHandler, 0)); #ifdef CONFIG_AWS_IOT_INTEGRATION int retAws = aws_iot_integration_register_callback(AWSIntegrationCallback); if (retAws) { LOG_ERR("aws_iot_integration_register_callback() failed"); return chip::System::MapErrorZephyr(retAws); } #endif //pj k_timer_init(&sSensorTimer, &SensorTimerHandler, nullptr); k_timer_user_data_set(&sSensorTimer, this); return Nrf::Matter::StartServer(); } CHIP_ERROR AppTask::StartApp() { ReturnErrorOnFailure(Init()); while (true) { Nrf::DispatchNextTask(); } return CHIP_NO_ERROR; }
using zap tool i add cluster