diff --git a/examples/common/imgui_ui/windows/BUILD.gn b/examples/common/imgui_ui/windows/BUILD.gn index 2f059c5325678a..390151142b78b9 100644 --- a/examples/common/imgui_ui/windows/BUILD.gn +++ b/examples/common/imgui_ui/windows/BUILD.gn @@ -51,6 +51,10 @@ static_library("light") { "${chip_root}/third_party/imgui", ] + # TODO: this is because on-off-server.h is generally only available + # in the app and we do not want to directly bind to lighting-app + check_includes = false + public_configs = [ "${chip_root}/src:includes" ] } diff --git a/examples/common/imgui_ui/windows/light.cpp b/examples/common/imgui_ui/windows/light.cpp index f16f2ff9de4150..fbfcdda48284a1 100644 --- a/examples/common/imgui_ui/windows/light.cpp +++ b/examples/common/imgui_ui/windows/light.cpp @@ -23,6 +23,9 @@ #include #include +#include +#include + namespace example { namespace Ui { namespace Windows { @@ -65,9 +68,35 @@ ImVec4 HueSaturationToColor(float hueDegrees, float saturationPercent) void Light::UpdateState() { + if (mTargetLightIsOn.HasValue()) + { + EmberAfStatus status = OnOffServer::Instance().setOnOffValue( + mEndpointId, mTargetLightIsOn.Value() ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id, + false /* initiatedByLevelChange */); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(AppServer, "Failed to set on/off value: %d", status); + } + + mTargetLightIsOn.ClearValue(); + } OnOff::Attributes::OnOff::Get(mEndpointId, &mLightIsOn); // Level Control + if (mTargetLevel.HasValue()) + { + LevelControl::Commands::MoveToLevel::DecodableType data; + + data.level = mTargetLevel.Value(); + data.optionsMask.Set(LevelControl::LevelControlOptions::kExecuteIfOff); + data.optionsOverride.Set(LevelControl::LevelControlOptions::kExecuteIfOff); + + (void) LevelControlServer::MoveToLevel(mEndpointId, data); + + mTargetLevel.ClearValue(); + } + LevelControl::Attributes::CurrentLevel::Get(mEndpointId, mCurrentLevel); LevelControl::Attributes::MinLevel::Get(mEndpointId, &mMinLevel); LevelControl::Attributes::MaxLevel::Get(mEndpointId, &mMaxLevel); @@ -88,15 +117,14 @@ void Light::Render() ImGui::Begin("Light state"); ImGui::Text("Light on endpoint %d", mEndpointId); - ImGui::Text("On-Off:"); ImGui::Indent(); - if (mLightIsOn) - { - ImGui::Text("Light is ON"); - } - else { - ImGui::Text("Light is OFF"); + bool uiValue = mLightIsOn; + ImGui::Checkbox("Light is ON", &uiValue); + if (uiValue != mLightIsOn) + { + mTargetLightIsOn.SetValue(uiValue); // schedule future update + } } // bright yellow vs dark yellow on/off view @@ -115,8 +143,12 @@ void Light::Render() } else { - int levelValue = mCurrentLevel.Value(); - ImGui::SliderInt("Current Level", &levelValue, mMinLevel, mMaxLevel); + int uiValue = mCurrentLevel.Value(); + ImGui::SliderInt("Current Level", &uiValue, mMinLevel, mMaxLevel); + if (uiValue != mCurrentLevel.Value()) + { + mTargetLevel.SetValue(uiValue); // schedule future update + } } ImGui::Unindent(); diff --git a/examples/common/imgui_ui/windows/light.h b/examples/common/imgui_ui/windows/light.h index 3636af5c6c1bd3..68d9cebb945da5 100644 --- a/examples/common/imgui_ui/windows/light.h +++ b/examples/common/imgui_ui/windows/light.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -45,11 +46,14 @@ class Light : public Window // OnOff bool mLightIsOn = false; + chip::Optional mTargetLightIsOn; // allow UI control of this // Level uint8_t mMinLevel = 0; uint8_t mMaxLevel = 0; chip::app::DataModel::Nullable mCurrentLevel; + chip::Optional mTargetLevel; // allow UI control of this + uint16_t mLevelRemainingTime10sOfSec = 0; // Color control diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 25989a7a8cc20e..8ad6844775226a 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -450,6 +450,14 @@ static bool shouldExecuteIfOff(EndpointId endpoint, CommandId commandId, bool emberAfLevelControlClusterMoveToLevelCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, const Commands::MoveToLevel::DecodableType & commandData) +{ + commandObj->AddStatus(commandPath, LevelControlServer::MoveToLevel(commandPath.mEndpointId, commandData)); + return true; +} + +namespace LevelControlServer { + +Status MoveToLevel(EndpointId endpointId, const Commands::MoveToLevel::DecodableType & commandData) { auto & level = commandData.level; auto & transitionTime = commandData.transitionTime; @@ -467,15 +475,12 @@ bool emberAfLevelControlClusterMoveToLevelCallback(app::CommandHandler * command optionsMask.Raw(), optionsOverride.Raw()); } - Status status = moveToLevelHandler(commandPath.mEndpointId, Commands::MoveToLevel::Id, level, transitionTime, - Optional>(optionsMask), - Optional>(optionsOverride), - INVALID_STORED_LEVEL); // Don't revert to the stored level - - commandObj->AddStatus(commandPath, status); - - return true; + return moveToLevelHandler(endpointId, Commands::MoveToLevel::Id, level, transitionTime, + Optional>(optionsMask), + Optional>(optionsOverride), + INVALID_STORED_LEVEL); // Don't revert to the stored level } +} // namespace LevelControlServer bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, diff --git a/src/app/clusters/level-control/level-control.h b/src/app/clusters/level-control/level-control.h index b1c5f2e51d0cd2..e4d2c6593ada22 100644 --- a/src/app/clusters/level-control/level-control.h +++ b/src/app/clusters/level-control/level-control.h @@ -27,8 +27,8 @@ #include #include +#include #include -#include /** @brief Level Control Cluster Server Post Init * @@ -45,3 +45,11 @@ void emberAfPluginLevelControlClusterServerPostInitCallback(chip::EndpointId end * fact an instance of Level Control on the given endpoint. */ bool LevelControlHasFeature(chip::EndpointId endpoint, chip::app::Clusters::LevelControl::LevelControlFeature feature); + +namespace LevelControlServer { + +chip::Protocols::InteractionModel::Status +MoveToLevel(chip::EndpointId endpointId, + const chip::app::Clusters::LevelControl::Commands::MoveToLevel::DecodableType & commandData); + +} // namespace LevelControlServer diff --git a/src/app/clusters/on-off-server/on-off-server.cpp b/src/app/clusters/on-off-server/on-off-server.cpp index 9ca45c3b55041d..1f62a3261635d7 100644 --- a/src/app/clusters/on-off-server/on-off-server.cpp +++ b/src/app/clusters/on-off-server/on-off-server.cpp @@ -48,6 +48,8 @@ using chip::Protocols::InteractionModel::Status; static OnOffEffect * firstEffect = nullptr; OnOffServer OnOffServer::instance; +static EmberEventControl gEventControls[EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT]; + /********************************************************** * Function definition *********************************************************/ @@ -650,15 +652,12 @@ bool OnOffServer::areStartUpOnOffServerAttributesNonVolatile(EndpointId endpoint */ EmberEventControl * OnOffServer::getEventControl(EndpointId endpoint) { - uint16_t index = emberAfFindClusterServerEndpointIndex(endpoint, OnOff::Id); - EmberEventControl * event = nullptr; - - if (index < ArraySize(eventControls)) + uint16_t index = emberAfFindClusterServerEndpointIndex(endpoint, OnOff::Id); + if (index >= ArraySize(gEventControls)) { - event = &eventControls[index]; + return nullptr; } - - return event; + return &gEventControls[index]; } /** diff --git a/src/app/clusters/on-off-server/on-off-server.h b/src/app/clusters/on-off-server/on-off-server.h index 45b34a992293cf..46f4eb4154675f 100644 --- a/src/app/clusters/on-off-server/on-off-server.h +++ b/src/app/clusters/on-off-server/on-off-server.h @@ -22,7 +22,6 @@ #include #include #include -#include #include using chip::app::Clusters::OnOff::OnOffFeature; @@ -95,7 +94,6 @@ class OnOffServer *********************************************************/ static OnOffServer instance; - EmberEventControl eventControls[EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT]; chip::System::Clock::Timestamp nextDesiredOnWithTimedOffTimestamp; };