Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/oven-app/silabs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ silabs_executable("oven_app") {
"src/DataModelCallbacks.cpp",
"src/OvenBindingHandler.cpp",
"src/OvenManager.cpp",
"src/OvenUI.cpp",
]

deps = [ ":sdk" ]
Expand Down
26 changes: 22 additions & 4 deletions examples/oven-app/silabs/include/AppTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ class AppTask : public BaseApplication
*/
static void ButtonEventHandler(uint8_t button, uint8_t btnAction);

/**
* @brief Updates the LED display with the current state
*
* @param value Current state value to display
*/
void UpdateLED(int8_t value);

/**
* @brief Updates the LCD display with current cook-top and oven-mode states
*/
void UpdateLCD();

private:
static AppTask sAppTask;

Expand All @@ -93,11 +105,17 @@ class AppTask : public BaseApplication
CHIP_ERROR AppInit() override;

/**
* @brief PB0 Button event processing function
* Press and hold will trigger a factory reset timer start
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not apply anymore?

* Press and release will restart BLEAdvertising if not commissioned
* @brief PB1 Button event processing function for oven functionality
* Press and release will toggle cooktop and cook surface states
*
* @param aEvent button event being processed
*/
static void ButtonHandler(AppEvent * aEvent);
static void OvenButtonHandler(AppEvent * aEvent);

/**
* @brief Updates the cluster state for button actions
*
* @param context Context parameter (unused)
*/
static void UpdateClusterState(intptr_t context);
};
38 changes: 37 additions & 1 deletion examples/oven-app/silabs/include/OvenManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,41 @@ class OvenManager
*/
bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode);

/**
* @brief Gets the current state of the CookTop.
*/
State_t GetCookTopState() const { return mCookTopState; }

/**
* @brief Gets the current oven mode.
*/
uint8_t GetCurrentOvenMode() { return mCurrentOvenMode; };

/**
* @brief Get the endpoint ID for the Oven endpoint
*/
static constexpr chip::EndpointId GetOvenEndpoint() { return kOvenEndpoint; }

/**
* @brief Get the endpoint ID for the Temperature Controlled Cabinet endpoint
*/
static constexpr chip::EndpointId GetTemperatureControlledCabinetEndpoint() { return kTemperatureControlledCabinetEndpoint; }

/**
* @brief Get the endpoint ID for the CookTop endpoint
*/
static constexpr chip::EndpointId GetCookTopEndpoint() { return kCookTopEndpoint; }

/**
* @brief Get the endpoint ID for the first CookSurface endpoint
*/
static constexpr chip::EndpointId GetCookSurfaceEndpoint1() { return kCookSurfaceEndpoint1; }

/**
* @brief Get the endpoint ID for the second CookSurface endpoint
*/
static constexpr chip::EndpointId GetCookSurfaceEndpoint2() { return kCookSurfaceEndpoint2; }

private:
struct BlockedTransition
{
Expand All @@ -145,6 +180,7 @@ class OvenManager
};

static OvenManager sOvenMgr;
uint8_t mCurrentOvenMode;
chip::app::Clusters::AppSupportedTemperatureLevelsDelegate mTemperatureControlDelegate;

State_t mCookTopState;
Expand All @@ -156,7 +192,7 @@ class OvenManager

static void ActuatorMovementHandler(AppEvent * aEvent);

// Define the endpoint ID for the Oven
// Define the endpoint ID constants
static constexpr chip::EndpointId kOvenEndpoint = 1;
static constexpr chip::EndpointId kTemperatureControlledCabinetEndpoint = 2;
static constexpr chip::EndpointId kCookTopEndpoint = 3;
Expand Down
38 changes: 38 additions & 0 deletions examples/oven-app/silabs/include/OvenUI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include "demo-ui-bitmaps.h"
#include "dmd.h"
#include "glib.h"
#include "lcd.h"

class OvenUI
{

public:
static void DrawUI(GLIB_Context_t * glibContext);

private:
static void DrawHeader(GLIB_Context_t * glibContext);
static void DrawCookTopState(GLIB_Context_t * glibContext);
static void DrawOvenMode(GLIB_Context_t * glibContext);
static void DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data,
uint32_t size);
};
124 changes: 99 additions & 25 deletions examples/oven-app/silabs/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
#include "AppConfig.h"
#include "AppEvent.h"
#include "LEDWidget.h"
#include "OvenBindingHandler.h"
#include "OvenUI.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended? Seems like double inclusion


#ifdef DISPLAY_ENABLED
#include "OvenUI.h"
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate include of 'OvenUI.h' - this header is already included at line 25. Remove this duplicate inclusion.

Suggested change
#include "OvenUI.h"

Copilot uses AI. Check for mistakes.
#include "lcd.h"
#ifdef QR_CODE_ENABLED
#include "qrcodegen.h"
Expand All @@ -36,6 +39,7 @@
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>
#include <app/clusters/network-commissioning/network-commissioning.h>
#include <app/clusters/on-off-server/on-off-server.h>
#include <app/server/Server.h>
#include <app/util/attribute-storage.h>
#include <app/util/endpoint-config-api.h>
Expand All @@ -48,6 +52,12 @@
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <setup_payload/SetupPayload.h>

#ifdef SL_CATALOG_SIMPLE_LED_LED1_PRESENT
#define LIGHT_LED 1
#else
#define LIGHT_LED 0
#endif

#define APP_FUNCTION_BUTTON 0
#define APP_ACTION_BUTTON 1

Expand All @@ -59,6 +69,8 @@ using namespace ::chip::DeviceLayer::Silabs;
using namespace ::chip::DeviceLayer::Internal;
using namespace chip::TLV;

LEDWidget sLightLED; // Use LEDWidget for basic LED functionality

AppTask AppTask::sAppTask;

CHIP_ERROR AppTask::AppInit()
Expand All @@ -68,20 +80,21 @@ CHIP_ERROR AppTask::AppInit()

#ifdef DISPLAY_ENABLED
GetLCD().Init((uint8_t *) "Oven-App");
GetLCD().SetCustomUI(OvenUI::DrawUI);
#endif

// Initialization of Oven Manager and endpoints of oven.
OvenManager::GetInstance().Init();
OvenManager::GetInstance().SetCallbacks(ActionInitiated, ActionCompleted);

sLightLED.Init(LIGHT_LED);
UpdateLED(OvenManager::GetInstance().GetCookTopState() == OvenManager::kCookTopState_OnCompleted);

// Update the LCD with the Stored value. Show QR Code if not provisioned
#ifdef DISPLAY_ENABLED
GetLCD().WriteDemoUI(false);
UpdateLCD();
#ifdef QR_CODE_ENABLED
#ifdef SL_WIFI
if (!ConnectivityMgr().IsWiFiStationProvisioned())
#else
if (!ConnectivityMgr().IsThreadProvisioned())
#endif /* !SL_WIFI */
if (!BaseApplication::GetProvisionStatus())
{
GetLCD().ShowQRCode(true);
}
Expand All @@ -108,6 +121,10 @@ void AppTask::AppTaskMain(void * pvParameter)
appError(err);
}

#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER)
sAppTask.StartStatusLEDTimer();
#endif

ChipLogProgress(AppServer, "App Task started");

while (true)
Expand All @@ -126,33 +143,31 @@ void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction)
AppEvent button_event = {};
button_event.Type = AppEvent::kEventType_Button;
button_event.ButtonEvent.Action = btnAction;
button_event.Handler = BaseApplication::ButtonHandler;

// Handle button1 specifically for oven functionality
if (button == APP_ACTION_BUTTON)
{
button_event.Handler = OvenButtonHandler;
}
else
{
button_event.Handler = BaseApplication::ButtonHandler;
}

AppTask::GetAppTask().PostEvent(&button_event);
}

void AppTask::ActionInitiated(OvenManager::Action_t aAction, int32_t aActor, uint8_t * aValue)
{
ChipLogProgress(AppServer, "ActionInitiated: %d, %ld", aAction, aActor);
if (aActor == AppEvent::kEventType_CookTop)
{
bool lightOn = aAction == OvenManager::ON_ACTION;
ChipLogProgress(AppServer, "Turning CookTop %s", (lightOn) ? "On" : "Off");

// TODO: Update LED state

#ifdef DISPLAY_ENABLED
sAppTask.GetLCD().WriteDemoUI(lightOn);
#endif
ChipLogProgress(AppServer, "Turning CookTop %s", (aAction == OvenManager::ON_ACTION) ? "On" : "Off");
}

if (aActor == AppEvent::kEventType_CookSurface)
{
bool lightOn = aAction == OvenManager::ON_ACTION;
ChipLogProgress(AppServer, "Turning CookSurface %s", (lightOn) ? "On" : "Off");
}

if (aActor == AppEvent::kEventType_Button)
{
sAppTask.mSyncClusterToButtonAction = true;
ChipLogProgress(AppServer, "Turning CookSurface %s", (aAction == OvenManager::ON_ACTION) ? "On" : "Off");
}
}

Expand All @@ -167,10 +182,69 @@ void AppTask::ActionCompleted(OvenManager::Action_t aAction)
{
ChipLogProgress(AppServer, "OFF action completed");
}
}

if (sAppTask.mSyncClusterToButtonAction)
void AppTask::OvenButtonHandler(AppEvent * aEvent)
{
// Handle button press to toggle cooktop and cook surface
if (aEvent->ButtonEvent.Action == static_cast<uint8_t>(SilabsPlatform::ButtonAction::ButtonPressed))
{
// TODO: Schedule work to Update CookTop and CookSurfaceEndpoints (turn on/off)
sAppTask.mSyncClusterToButtonAction = false;
ChipLogProgress(AppServer, "Oven button pressed - starting toggle action");
return; // Only handle button release
}

if (aEvent->ButtonEvent.Action == static_cast<uint8_t>(SilabsPlatform::ButtonAction::ButtonReleased))
{
ChipLogProgress(AppServer, "Oven button released - toggling cooktop and cook surface");

// Determine new state (toggle current state)
OvenManager::Action_t action = (OvenManager::GetInstance().GetCookTopState() == OvenManager::kCookTopState_OnCompleted)
? OvenManager::OFF_ACTION
: OvenManager::ON_ACTION;

// Toggle CookTop
chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast<intptr_t>(nullptr));
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using reinterpret_cast<intptr_t>(nullptr) is unnecessarily complex. Since the UpdateClusterState function doesn't use the context parameter, pass 0 directly or use static_cast<intptr_t>(0) for clarity.

Suggested change
chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast<intptr_t>(nullptr));
chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, 0);

Copilot uses AI. Check for mistakes.

// Trigger binding for cooktop endpoint (this will send commands to bound Matter devices)
OnOffBindingContext * context = Platform::New<OnOffBindingContext>();
if (context != nullptr)
{
context->localEndpointId = OvenManager::GetCookTopEndpoint(); // CookTop endpoint
context->commandId = (action == OvenManager::ON_ACTION) ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id;

ChipLogProgress(AppServer, "Triggering binding for cooktop endpoint with command %lu",
static_cast<unsigned long>(context->commandId));
CookTopOnOffBindingTrigger(context);
}
}
}

void AppTask::UpdateClusterState(intptr_t context)
{
// Update the OnOff cluster state for the cooktop endpoint based on the current state
bool currentState = (OvenManager::GetInstance().GetCookTopState() == OvenManager::kCookTopState_OnCompleted);

ChipLogProgress(AppServer, "Updating cooktop OnOff cluster state to %s", currentState ? "On" : "Off");

// Set the OnOff attribute value for the cooktop endpoint
Protocols::InteractionModel::Status status =
OnOffServer::Instance().setOnOffValue(OvenManager::GetCookTopEndpoint(), currentState, false);
Comment on lines +227 to +231
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OnOff cluster is being set to the current state rather than the new toggled state. Line 225 reads the current state, but the toggle logic should invert this value before setting it. The state should be !currentState to achieve the toggle behavior.

Suggested change
ChipLogProgress(AppServer, "Updating cooktop OnOff cluster state to %s", currentState ? "On" : "Off");
// Set the OnOff attribute value for the cooktop endpoint
Protocols::InteractionModel::Status status =
OnOffServer::Instance().setOnOffValue(OvenManager::GetCookTopEndpoint(), currentState, false);
ChipLogProgress(AppServer, "Updating cooktop OnOff cluster state to %s", !currentState ? "On" : "Off");
// Set the OnOff attribute value for the cooktop endpoint
Protocols::InteractionModel::Status status =
OnOffServer::Instance().setOnOffValue(OvenManager::GetCookTopEndpoint(), !currentState, false);

Copilot uses AI. Check for mistakes.

if (status != Protocols::InteractionModel::Status::Success)
{
ChipLogError(AppServer, "Failed to update cooktop OnOff cluster state: %x", to_underlying(status));
}
}

void AppTask::UpdateLED(int8_t value)
{
sLightLED.Set(value);
}

void AppTask::UpdateLCD()
{
// Update the LCD with the Stored value.
#ifdef DISPLAY_ENABLED
GetLCD().WriteDemoUI(false);
#endif // DISPLAY_ENABLED
}
16 changes: 13 additions & 3 deletions examples/oven-app/silabs/src/OvenManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,14 @@ void OvenManager::Init()
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(AppServer, "RegisterSupportedLevels failed for CookSurfaceEndpoint2"));

// Get CookTop On/Off value
// OnOffServer::Instance().getOnOffValue(1, &currentLedState);
// mCookTopState = currentLedState ? kState_OnCompleted : kState_OffCompleted;
bool currentLedState = false;
chip::Protocols::InteractionModel::Status status = OnOffServer::Instance().getOnOffValue(kCookTopEndpoint, &currentLedState);
VerifyOrReturn(status == Status::Success, ChipLogError(AppServer, "Failed to get CookTop OnOff value"));
mCookTopState = currentLedState ? kCookTopState_OnCompleted : kCookTopState_OffCompleted;

// Get current oven mode
status = OvenMode::Attributes::CurrentMode::Get(kTemperatureControlledCabinetEndpoint, &mCurrentOvenMode);
VerifyOrReturn(status == Status::Success, ChipLogError(AppServer, "Unable to get the current oven mode"));

DeviceLayer::PlatformMgr().UnlockChipStack();

Expand Down Expand Up @@ -181,6 +187,8 @@ void OvenManager::OnOffAttributeChangeHandler(EndpointId endpointId, AttributeId

CookTopOnOffBindingTrigger(context);
}
AppTask::GetAppTask().UpdateLED(*value);
AppTask::GetAppTask().UpdateLCD();
break;
case kCookSurfaceEndpoint1:
case kCookSurfaceEndpoint2:
Expand Down Expand Up @@ -209,7 +217,9 @@ void OvenManager::OvenModeAttributeChangeHandler(chip::EndpointId endpointId, ch
{
VerifyOrReturn(endpointId == kTemperatureControlledCabinetEndpoint,
ChipLogError(AppServer, "Command received over Unsupported Endpoint"));
// TODO: Update the LCD with the new Oven Mode

mCurrentOvenMode = *value;
AppTask::GetAppTask().UpdateLCD();
return;
}

Expand Down
Loading
Loading