Skip to content

Commit

Permalink
Add UI support for controlling the light app (#25160)
Browse files Browse the repository at this point in the history
* Control support for light app

* Use the light on-off-server to drive UI logic: make it seem like a on off command

* Make level control also work with the server values

* Restyle

* Undo an unneeded edit

* Remove initializer - static should be 0-filled anyway

* Update static variable to file local instead of function-local

---------

Co-authored-by: Andrei Litvin <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Oct 13, 2023
1 parent d333457 commit 1179334
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 27 deletions.
4 changes: 4 additions & 0 deletions examples/common/imgui_ui/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
}

Expand Down
50 changes: 41 additions & 9 deletions examples/common/imgui_ui/windows/light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-enums.h>

#include <app/clusters/level-control/level-control.h>
#include <app/clusters/on-off-server/on-off-server.h>

namespace example {
namespace Ui {
namespace Windows {
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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();

Expand Down
4 changes: 4 additions & 0 deletions examples/common/imgui_ui/windows/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <app/data-model/Nullable.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/Optional.h>

#include <app-common/zap-generated/cluster-enums.h>

Expand All @@ -45,11 +46,14 @@ class Light : public Window

// OnOff
bool mLightIsOn = false;
chip::Optional<bool> mTargetLightIsOn; // allow UI control of this

// Level
uint8_t mMinLevel = 0;
uint8_t mMaxLevel = 0;
chip::app::DataModel::Nullable<uint8_t> mCurrentLevel;
chip::Optional<uint8_t> mTargetLevel; // allow UI control of this

uint16_t mLevelRemainingTime10sOfSec = 0;

// Color control
Expand Down
21 changes: 13 additions & 8 deletions src/app/clusters/level-control/level-control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -467,15 +475,12 @@ bool emberAfLevelControlClusterMoveToLevelCallback(app::CommandHandler * command
optionsMask.Raw(), optionsOverride.Raw());
}

Status status = moveToLevelHandler(commandPath.mEndpointId, Commands::MoveToLevel::Id, level, transitionTime,
Optional<BitMask<LevelControlOptions>>(optionsMask),
Optional<BitMask<LevelControlOptions>>(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<BitMask<LevelControlOptions>>(optionsMask),
Optional<BitMask<LevelControlOptions>>(optionsOverride),
INVALID_STORED_LEVEL); // Don't revert to the stored level
}
} // namespace LevelControlServer

bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(app::CommandHandler * commandObj,
const app::ConcreteCommandPath & commandPath,
Expand Down
10 changes: 9 additions & 1 deletion src/app/clusters/level-control/level-control.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
#include <stdint.h>

#include <app-common/zap-generated/cluster-enums.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/util/basic-types.h>
#include <app/util/config.h>

/** @brief Level Control Cluster Server Post Init
*
Expand All @@ -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
13 changes: 6 additions & 7 deletions src/app/clusters/on-off-server/on-off-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*********************************************************/
Expand Down Expand Up @@ -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];
}

/**
Expand Down
2 changes: 0 additions & 2 deletions src/app/clusters/on-off-server/on-off-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <app/ConcreteCommandPath.h>
#include <app/util/af-types.h>
#include <app/util/basic-types.h>
#include <app/util/config.h>
#include <platform/CHIPDeviceConfig.h>

using chip::app::Clusters::OnOff::OnOffFeature;
Expand Down Expand Up @@ -95,7 +94,6 @@ class OnOffServer
*********************************************************/

static OnOffServer instance;
EmberEventControl eventControls[EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT];
chip::System::Clock::Timestamp nextDesiredOnWithTimedOffTimestamp;
};

Expand Down

0 comments on commit 1179334

Please sign in to comment.