diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index 1187aed537dfa7..f34dda3d819758 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -490,6 +490,131 @@ cluster OnOff = 6 { command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66; } +/** Attributes and commands for controlling devices that can be set to a level between fully 'On' and fully 'Off.' */ +cluster LevelControl = 8 { + revision 6; + + enum MoveModeEnum : enum8 { + kUp = 0; + kDown = 1; + } + + enum StepModeEnum : enum8 { + kUp = 0; + kDown = 1; + } + + bitmap Feature : bitmap32 { + kOnOff = 0x1; + kLighting = 0x2; + kFrequency = 0x4; + } + + bitmap OptionsBitmap : bitmap8 { + kExecuteIfOff = 0x1; + kCoupleColorTempToLevel = 0x2; + } + + readonly attribute nullable int8u currentLevel = 0; + readonly attribute optional int16u remainingTime = 1; + readonly attribute optional int8u minLevel = 2; + readonly attribute optional int8u maxLevel = 3; + readonly attribute optional int16u currentFrequency = 4; + readonly attribute optional int16u minFrequency = 5; + readonly attribute optional int16u maxFrequency = 6; + attribute OptionsBitmap options = 15; + attribute optional int16u onOffTransitionTime = 16; + attribute nullable int8u onLevel = 17; + attribute optional nullable int16u onTransitionTime = 18; + attribute optional nullable int16u offTransitionTime = 19; + attribute optional nullable int8u defaultMoveRate = 20; + attribute access(write: manage) optional nullable int8u startUpCurrentLevel = 16384; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct MoveToLevelRequest { + int8u level = 0; + nullable int16u transitionTime = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct MoveRequest { + MoveModeEnum moveMode = 0; + nullable int8u rate = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct StepRequest { + StepModeEnum stepMode = 0; + int8u stepSize = 1; + nullable int16u transitionTime = 2; + OptionsBitmap optionsMask = 3; + OptionsBitmap optionsOverride = 4; + } + + request struct StopRequest { + OptionsBitmap optionsMask = 0; + OptionsBitmap optionsOverride = 1; + } + + request struct MoveToLevelWithOnOffRequest { + int8u level = 0; + nullable int16u transitionTime = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct MoveWithOnOffRequest { + MoveModeEnum moveMode = 0; + nullable int8u rate = 1; + OptionsBitmap optionsMask = 2; + OptionsBitmap optionsOverride = 3; + } + + request struct StepWithOnOffRequest { + StepModeEnum stepMode = 0; + int8u stepSize = 1; + nullable int16u transitionTime = 2; + OptionsBitmap optionsMask = 3; + OptionsBitmap optionsOverride = 4; + } + + request struct StopWithOnOffRequest { + OptionsBitmap optionsMask = 0; + OptionsBitmap optionsOverride = 1; + } + + request struct MoveToClosestFrequencyRequest { + int16u frequency = 0; + } + + /** Command description for MoveToLevel */ + command MoveToLevel(MoveToLevelRequest): DefaultSuccess = 0; + /** Command description for Move */ + command Move(MoveRequest): DefaultSuccess = 1; + /** Command description for Step */ + command Step(StepRequest): DefaultSuccess = 2; + /** Command description for Stop */ + command Stop(StopRequest): DefaultSuccess = 3; + /** Command description for MoveToLevelWithOnOff */ + command MoveToLevelWithOnOff(MoveToLevelWithOnOffRequest): DefaultSuccess = 4; + /** Command description for MoveWithOnOff */ + command MoveWithOnOff(MoveWithOnOffRequest): DefaultSuccess = 5; + /** Command description for StepWithOnOff */ + command StepWithOnOff(StepWithOnOffRequest): DefaultSuccess = 6; + /** Command description for StopWithOnOff */ + command StopWithOnOff(StopWithOnOffRequest): DefaultSuccess = 7; + /** Change the currrent frequency to the provided one, or a close + approximation if the exact provided one is not possible. */ + command MoveToClosestFrequency(MoveToClosestFrequencyRequest): DefaultSuccess = 8; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; @@ -3158,10 +3283,11 @@ endpoint 0 { } } endpoint 1 { - device type ma_onofflightswitch = 259, version 1; + device type ma_dimmerswitch = 260, version 1; binding cluster Identify; binding cluster OnOff; + binding cluster LevelControl; binding cluster ScenesManagement; binding cluster ColorControl; diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.zap b/examples/light-switch-app/light-switch-common/light-switch-app.zap index d0f7a6a638b8a8..4cb3c0813ba990 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.zap +++ b/examples/light-switch-app/light-switch-common/light-switch-app.zap @@ -4402,20 +4402,20 @@ }, { "id": 2, - "name": "MA-onofflightswitch", + "name": "MA-dimmerswitch", "deviceTypeRef": { - "code": 259, + "code": 260, "profileId": 259, - "label": "MA-onofflightswitch", - "name": "MA-onofflightswitch", + "label": "MA-dimmerswitch", + "name": "MA-dimmerswitch", "deviceTypeOrder": 0 }, "deviceTypes": [ { - "code": 259, + "code": 260, "profileId": 259, - "label": "MA-onofflightswitch", - "name": "MA-onofflightswitch", + "label": "MA-dimmerswitch", + "name": "MA-dimmerswitch", "deviceTypeOrder": 0 } ], @@ -4423,10 +4423,10 @@ 1 ], "deviceIdentifiers": [ - 259 + 260 ], - "deviceTypeName": "MA-onofflightswitch", - "deviceTypeCode": 259, + "deviceTypeName": "MA-dimmerswitch", + "deviceTypeCode": 260, "deviceTypeProfileId": 259, "clusters": [ { @@ -4737,6 +4737,80 @@ } ] }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "MoveToLevel", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "Move", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "Step", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "Stop", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "MoveToLevelWithOnOff", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "MoveWithOnOff", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "StepWithOnOff", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "StopWithOnOff", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, { "name": "Descriptor", "code": 29, @@ -5639,7 +5713,7 @@ "parentEndpointIdentifier": null }, { - "endpointTypeName": "MA-onofflightswitch", + "endpointTypeName": "MA-dimmerswitch", "endpointTypeIndex": 1, "profileId": 259, "endpointId": 1, diff --git a/examples/light-switch-app/silabs/include/AppConfig.h b/examples/light-switch-app/silabs/include/AppConfig.h index 6276e25761f910..976c0ed5105d94 100644 --- a/examples/light-switch-app/silabs/include/AppConfig.h +++ b/examples/light-switch-app/silabs/include/AppConfig.h @@ -31,6 +31,8 @@ // state to another. #define ACTUATOR_MOVEMENT_PERIOS_MS 10 +#define LONG_PRESS_TIMEOUT 3000 + // APP Logo, boolean only. must be 64x64 #define ON_DEMO_BITMAP \ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ diff --git a/examples/light-switch-app/silabs/include/AppEvent.h b/examples/light-switch-app/silabs/include/AppEvent.h index 7a19b719edad25..10564c2fc52ae4 100644 --- a/examples/light-switch-app/silabs/include/AppEvent.h +++ b/examples/light-switch-app/silabs/include/AppEvent.h @@ -19,6 +19,8 @@ #pragma once +#include + struct AppEvent; typedef void (*EventHandler)(AppEvent *); @@ -30,6 +32,15 @@ struct AppEvent kEventType_Timer, kEventType_Light, kEventType_Install, + kEventType_ResetWarning, + kEventType_ResetCanceled, + // Button events + kEventType_ActionButtonPressed, + kEventType_ActionButtonReleased, + kEventType_FunctionButtonPressed, + kEventType_FunctionButtonReleased, + kEventType_TriggerLevelControlAction, + kEventType_TriggerToggle, }; uint16_t Type; @@ -46,9 +57,8 @@ struct AppEvent } TimerEvent; struct { - uint8_t Action; - int32_t Actor; - } LightEvent; + void * Context; + } LightSwitchEvent; }; EventHandler Handler; diff --git a/examples/light-switch-app/silabs/include/AppTask.h b/examples/light-switch-app/silabs/include/AppTask.h index 1f014fb11d85d1..6133d05c492ec0 100644 --- a/examples/light-switch-app/silabs/include/AppTask.h +++ b/examples/light-switch-app/silabs/include/AppTask.h @@ -66,16 +66,6 @@ class AppTask : public BaseApplication CHIP_ERROR StartAppTask(); - /** - * @brief Event handler when a button is pressed - * Function posts an event for button processing - * - * @param buttonHandle APP_LIGHT_SWITCH or APP_FUNCTION_BUTTON - * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, - * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED - */ - static void ButtonEventHandler(uint8_t button, uint8_t btnAction); - private: static AppTask sAppTask; @@ -85,21 +75,4 @@ class AppTask : public BaseApplication * @return CHIP_ERROR */ CHIP_ERROR AppInit() override; - - /** - * @brief PB0 Button event processing function - * Press and hold will trigger a factory reset timer start - * Press and release will restart BLEAdvertising if not commisionned - * - * @param aEvent button event being processed - */ - static void ButtonHandler(AppEvent * aEvent); - - /** - * @brief PB1 Button event processing function - * Function triggers a switch action sent to the CHIP task - * - * @param aEvent button event being processed - */ - static void SwitchActionEventHandler(AppEvent * aEvent); }; diff --git a/examples/light-switch-app/silabs/include/BindingHandler.h b/examples/light-switch-app/silabs/include/BindingHandler.h index aed08be25eb5bc..bc09a72eef6622 100644 --- a/examples/light-switch-app/silabs/include/BindingHandler.h +++ b/examples/light-switch-app/silabs/include/BindingHandler.h @@ -19,15 +19,54 @@ #include "app-common/zap-generated/ids/Clusters.h" #include "app-common/zap-generated/ids/Commands.h" #include "lib/core/CHIPError.h" +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::LevelControl; CHIP_ERROR InitBindingHandler(); void SwitchWorkerFunction(intptr_t context); void BindingWorkerFunction(intptr_t context); +struct CommandBase +{ + chip::BitMask optionsMask; + chip::BitMask optionsOverride; + + // Constructor to initialize the BitMask + CommandBase() : optionsMask(0), optionsOverride(0) {} +}; + struct BindingCommandData { chip::EndpointId localEndpointId = 1; chip::CommandId commandId; chip::ClusterId clusterId; bool isGroup = false; + + struct MoveToLevel : public CommandBase + { + uint8_t level; + DataModel::Nullable transitionTime; + }; + struct Move : public CommandBase + { + MoveModeEnum moveMode; + DataModel::Nullable rate; + }; + struct Step : public CommandBase + { + StepModeEnum stepMode; + uint8_t stepSize; + DataModel::Nullable transitionTime; + }; + struct Stop : public CommandBase + { + // Inherits optionsMask and optionsOverride from CommandBase + }; + // Use std::variant to hold different command types + std::variant commandData; }; diff --git a/examples/light-switch-app/silabs/include/LightSwitchMgr.h b/examples/light-switch-app/silabs/include/LightSwitchMgr.h index adfe75fda9512e..e5bf3b33db9990 100644 --- a/examples/light-switch-app/silabs/include/LightSwitchMgr.h +++ b/examples/light-switch-app/silabs/include/LightSwitchMgr.h @@ -19,10 +19,19 @@ #pragma once +#include "AppEvent.h" +#include +#include #include +#include #include #include +#include +#include +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::LevelControl; class LightSwitchMgr { public: @@ -39,20 +48,88 @@ class LightSwitchMgr chip::EventId event; }; + static constexpr Clusters::LevelControl::Commands::Step::Type stepCommand = { + .stepSize = 1, .transitionTime = 0, .optionsMask = 0, .optionsOverride = 0 + }; + + struct Timer + { + typedef void (*Callback)(Timer & timer); + + Timer(uint32_t timeoutInMs, Callback callback, void * context); + ~Timer(); + + void Start(); + void Stop(); + void Timeout(); + + Callback mCallback = nullptr; + void * mContext = nullptr; + bool mIsActive = false; + + osTimerId_t mHandler = nullptr; + + private: + static void TimerCallback(void * timerCbArg); + }; + CHIP_ERROR Init(chip::EndpointId lightSwitchEndpoint, chip::EndpointId genericSwitchEndpoint); void GenericSwitchOnInitialPress(); void GenericSwitchOnShortRelease(); void TriggerLightSwitchAction(LightSwitchAction action, bool isGroupCommand = false); + void TriggerLevelControlAction(StepModeEnum stepMode, bool isGroupCommand = false); + + StepModeEnum getStepMode(); + + AppEvent CreateNewEvent(AppEvent::AppEventTypes type); static LightSwitchMgr & GetInstance() { return sSwitch; } + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param button BUTTON0 or BUTTON1 + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED + */ + static void ButtonEventHandler(uint8_t button, uint8_t btnAction); + + static void AppEventHandler(AppEvent * aEvent); + private: static LightSwitchMgr sSwitch; + Timer * mLongPressTimer = nullptr; + bool mFunctionButtonPressed = false; // True when button0 is pressed, used to trigger factory reset + bool mActionButtonPressed = false; // True when button1 is pressed, used to initiate toggle or level-up/down + bool mActionButtonSuppressed = false; // True when both button0 and button1 are pressed, used to switch step direction + bool mResetWarning = false; + + // Default Step direction for Level control + StepModeEnum stepDirection = StepModeEnum::kUp; + + static void OnLongPressTimeout(Timer & timer); + LightSwitchMgr() = default; + + /** + * @brief This function will be called when PB0 is + * long-pressed to trigger the factory-reset + */ + void HandleLongPress(); + static void GenericSwitchWorkerFunction(intptr_t context); chip::EndpointId mLightSwitchEndpoint = chip::kInvalidEndpointId; chip::EndpointId mGenericSwitchEndpoint = chip::kInvalidEndpointId; + + /** + * @brief Button event processing function + * Function triggers a switch action sent to the CHIP task + * + * @param aEvent button event being processed + */ + static void SwitchActionEventHandler(AppEvent * aEvent); }; diff --git a/examples/light-switch-app/silabs/src/AppTask.cpp b/examples/light-switch-app/silabs/src/AppTask.cpp index 5859d592152bad..14e8f3c609bed6 100644 --- a/examples/light-switch-app/silabs/src/AppTask.cpp +++ b/examples/light-switch-app/silabs/src/AppTask.cpp @@ -49,9 +49,6 @@ #define SYSTEM_STATE_LED &sl_led_led0 -#define APP_FUNCTION_BUTTON 0 -#define APP_LIGHT_SWITCH 1 - namespace { constexpr chip::EndpointId kLightSwitchEndpoint = 1; constexpr chip::EndpointId kGenericSwitchEndpoint = 2; @@ -74,7 +71,7 @@ AppTask AppTask::sAppTask; CHIP_ERROR AppTask::AppInit() { CHIP_ERROR err = CHIP_NO_ERROR; - chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler); + chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(LightSwitchMgr::ButtonEventHandler); err = LightSwitchMgr::GetInstance().Init(kLightSwitchEndpoint, kGenericSwitchEndpoint); if (err != CHIP_NO_ERROR) @@ -118,46 +115,3 @@ void AppTask::AppTaskMain(void * pvParameter) } } } - -void AppTask::SwitchActionEventHandler(AppEvent * aEvent) -{ - VerifyOrReturn(aEvent->Type == AppEvent::kEventType_Button); - - static bool mCurrentButtonState = false; - - if (aEvent->ButtonEvent.Action == static_cast(SilabsPlatform::ButtonAction::ButtonPressed)) - { - mCurrentButtonState = !mCurrentButtonState; - LightSwitchMgr::LightSwitchAction action = - mCurrentButtonState ? LightSwitchMgr::LightSwitchAction::On : LightSwitchMgr::LightSwitchAction::Off; - - LightSwitchMgr::GetInstance().TriggerLightSwitchAction(action); - LightSwitchMgr::GetInstance().GenericSwitchOnInitialPress(); - -#ifdef DISPLAY_ENABLED - sAppTask.GetLCD().WriteDemoUI(mCurrentButtonState); -#endif - } - else if (aEvent->ButtonEvent.Action == static_cast(SilabsPlatform::ButtonAction::ButtonReleased)) - { - LightSwitchMgr::GetInstance().GenericSwitchOnShortRelease(); - } -} - -void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) -{ - AppEvent button_event = {}; - button_event.Type = AppEvent::kEventType_Button; - button_event.ButtonEvent.Action = btnAction; - - if (button == APP_LIGHT_SWITCH) - { - button_event.Handler = SwitchActionEventHandler; - sAppTask.PostEvent(&button_event); - } - else if (button == APP_FUNCTION_BUTTON) - { - button_event.Handler = BaseApplication::ButtonHandler; - sAppTask.PostEvent(&button_event); - } -} diff --git a/examples/light-switch-app/silabs/src/BindingHandler.cpp b/examples/light-switch-app/silabs/src/BindingHandler.cpp index 56f7c306f989d8..0165fdc437cd40 100644 --- a/examples/light-switch-app/silabs/src/BindingHandler.cpp +++ b/examples/light-switch-app/silabs/src/BindingHandler.cpp @@ -28,6 +28,7 @@ using namespace chip; using namespace chip::app; +using namespace chip::app::Clusters::LevelControl; namespace { @@ -85,6 +86,247 @@ void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTabl } } +void ProcessLevelControlUnicastBindingCommand(BindingCommandData * data, const EmberBindingTableEntry & binding, + OperationalDeviceProxy * peer_device) +{ + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + ChipLogProgress(NotSpecified, "LevelControl command succeeds"); + }; + + auto onFailure = [](CHIP_ERROR error) { + ChipLogError(NotSpecified, "LevelControl command failed: %" CHIP_ERROR_FORMAT, error.Format()); + }; + + VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady()); + + switch (data->commandId) + { + case Clusters::LevelControl::Commands::MoveToLevel::Id: { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + if (auto moveToLevel = std::get_if(&data->commandData)) + { + moveToLevelCommand.level = moveToLevel->level; + moveToLevelCommand.transitionTime = moveToLevel->transitionTime; + moveToLevelCommand.optionsMask = moveToLevel->optionsMask; + moveToLevelCommand.optionsOverride = moveToLevel->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, moveToLevelCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::Move::Id: { + Clusters::LevelControl::Commands::Move::Type moveCommand; + if (auto move = std::get_if(&data->commandData)) + { + moveCommand.moveMode = move->moveMode; + moveCommand.rate = move->rate; + moveCommand.optionsMask = move->optionsMask; + moveCommand.optionsOverride = move->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, moveCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::Step::Id: { + Clusters::LevelControl::Commands::Step::Type stepCommand; + if (auto step = std::get_if(&data->commandData)) + { + stepCommand.stepMode = step->stepMode; + stepCommand.stepSize = step->stepSize; + stepCommand.transitionTime = step->transitionTime; + stepCommand.optionsMask = step->optionsMask; + stepCommand.optionsOverride = step->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, stepCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::Stop::Id: { + Clusters::LevelControl::Commands::Stop::Type stopCommand; + if (auto stop = std::get_if(&data->commandData)) + { + stopCommand.optionsMask = stop->optionsMask; + stopCommand.optionsOverride = stop->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, stopCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id: { + Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Type moveToLevelWithOnOffCommand; + if (auto moveToLevel = std::get_if(&data->commandData)) + { + moveToLevelWithOnOffCommand.level = moveToLevel->level; + moveToLevelWithOnOffCommand.transitionTime = moveToLevel->transitionTime; + moveToLevelWithOnOffCommand.optionsMask = moveToLevel->optionsMask; + moveToLevelWithOnOffCommand.optionsOverride = moveToLevel->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, moveToLevelWithOnOffCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::MoveWithOnOff::Id: { + Clusters::LevelControl::Commands::MoveWithOnOff::Type moveWithOnOffCommand; + if (auto move = std::get_if(&data->commandData)) + { + moveWithOnOffCommand.moveMode = move->moveMode; + moveWithOnOffCommand.rate = move->rate; + moveWithOnOffCommand.optionsMask = move->optionsMask; + moveWithOnOffCommand.optionsOverride = move->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, moveWithOnOffCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::StepWithOnOff::Id: { + Clusters::LevelControl::Commands::StepWithOnOff::Type stepWithOnOffCommand; + if (auto step = std::get_if(&data->commandData)) + { + stepWithOnOffCommand.stepMode = step->stepMode; + stepWithOnOffCommand.stepSize = step->stepSize; + stepWithOnOffCommand.transitionTime = step->transitionTime; + stepWithOnOffCommand.optionsMask = step->optionsMask; + stepWithOnOffCommand.optionsOverride = step->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, stepWithOnOffCommand, onSuccess, onFailure); + } + break; + } + + case Clusters::LevelControl::Commands::StopWithOnOff::Id: { + Clusters::LevelControl::Commands::StopWithOnOff::Type stopWithOnOffCommand; + if (auto stop = std::get_if(&data->commandData)) + { + stopWithOnOffCommand.optionsMask = stop->optionsMask; + stopWithOnOffCommand.optionsOverride = stop->optionsOverride; + Controller::InvokeCommandRequest(peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), + binding.remote, stopWithOnOffCommand, onSuccess, onFailure); + } + break; + } + default: + break; + } +} + +void ProcessLevelControlGroupBindingCommand(BindingCommandData * data, const EmberBindingTableEntry & binding) +{ + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + + switch (data->commandId) + { + case Clusters::LevelControl::Commands::MoveToLevel::Id: { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + if (auto moveToLevel = std::get_if(&data->commandData)) + { + moveToLevelCommand.level = moveToLevel->level; + moveToLevelCommand.transitionTime = moveToLevel->transitionTime; + moveToLevelCommand.optionsMask = moveToLevel->optionsMask; + moveToLevelCommand.optionsOverride = moveToLevel->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToLevelCommand); + } + break; + } + + case Clusters::LevelControl::Commands::Move::Id: { + Clusters::LevelControl::Commands::Move::Type moveCommand; + if (auto move = std::get_if(&data->commandData)) + { + moveCommand.moveMode = move->moveMode; + moveCommand.rate = move->rate; + moveCommand.optionsMask = move->optionsMask; + moveCommand.optionsOverride = move->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveCommand); + } + break; + } + + case Clusters::LevelControl::Commands::Step::Id: { + Clusters::LevelControl::Commands::Step::Type stepCommand; + if (auto step = std::get_if(&data->commandData)) + { + stepCommand.stepMode = step->stepMode; + stepCommand.stepSize = step->stepSize; + stepCommand.transitionTime = step->transitionTime; + stepCommand.optionsMask = step->optionsMask; + stepCommand.optionsOverride = step->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, stepCommand); + } + break; + } + + case Clusters::LevelControl::Commands::Stop::Id: { + Clusters::LevelControl::Commands::Stop::Type stopCommand; + if (auto stop = std::get_if(&data->commandData)) + { + stopCommand.optionsMask = stop->optionsMask; + stopCommand.optionsOverride = stop->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, stopCommand); + } + break; + } + + case Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id: { + Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Type moveToLevelWithOnOffCommand; + if (auto moveToLevel = std::get_if(&data->commandData)) + { + moveToLevelWithOnOffCommand.level = moveToLevel->level; + moveToLevelWithOnOffCommand.transitionTime = moveToLevel->transitionTime; + moveToLevelWithOnOffCommand.optionsMask = moveToLevel->optionsMask; + moveToLevelWithOnOffCommand.optionsOverride = moveToLevel->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToLevelWithOnOffCommand); + } + break; + } + + case Clusters::LevelControl::Commands::MoveWithOnOff::Id: { + Clusters::LevelControl::Commands::MoveWithOnOff::Type moveWithOnOffCommand; + if (auto move = std::get_if(&data->commandData)) + { + moveWithOnOffCommand.moveMode = move->moveMode; + moveWithOnOffCommand.rate = move->rate; + moveWithOnOffCommand.optionsMask = move->optionsMask; + moveWithOnOffCommand.optionsOverride = move->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveWithOnOffCommand); + } + break; + } + + case Clusters::LevelControl::Commands::StepWithOnOff::Id: { + Clusters::LevelControl::Commands::StepWithOnOff::Type stepWithOnOffCommand; + if (auto step = std::get_if(&data->commandData)) + { + stepWithOnOffCommand.stepMode = step->stepMode; + stepWithOnOffCommand.stepSize = step->stepSize; + stepWithOnOffCommand.transitionTime = step->transitionTime; + stepWithOnOffCommand.optionsMask = step->optionsMask; + stepWithOnOffCommand.optionsOverride = step->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, stepWithOnOffCommand); + } + break; + } + + case Clusters::LevelControl::Commands::StopWithOnOff::Id: { + Clusters::LevelControl::Commands::StopWithOnOff::Type stopWithOnOffCommand; + if (auto stop = std::get_if(&data->commandData)) + { + stopWithOnOffCommand.optionsMask = stop->optionsMask; + stopWithOnOffCommand.optionsOverride = stop->optionsOverride; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, stopWithOnOffCommand); + } + break; + } + default: + break; + } +} + void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context) { VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null")); @@ -97,6 +339,9 @@ void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, Operation case Clusters::OnOff::Id: ProcessOnOffGroupBindingCommand(data->commandId, binding); break; + case Clusters::LevelControl::Id: + ProcessLevelControlGroupBindingCommand(data, binding); + break; } } else if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) @@ -108,6 +353,9 @@ void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, Operation ProcessOnOffUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value()); break; + case Clusters::LevelControl::Id: + ProcessLevelControlUnicastBindingCommand(data, binding, peer_device); + break; } } } @@ -139,6 +387,8 @@ void SwitchWorkerFunction(intptr_t context) BindingCommandData * data = reinterpret_cast(context); BindingManager::GetInstance().NotifyBoundClusterChanged(data->localEndpointId, data->clusterId, static_cast(data)); + + Platform::Delete(data); } void BindingWorkerFunction(intptr_t context) diff --git a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp index b33ac42630b80c..4c0ee0cad6cb51 100644 --- a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp +++ b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp @@ -26,18 +26,130 @@ #include "AppConfig.h" #include "AppEvent.h" +#include "AppTask.h" #include #include #include +#include #include +#include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; +using namespace chip::DeviceLayer; +using namespace chip::DeviceLayer::Silabs; LightSwitchMgr LightSwitchMgr::sSwitch; +AppEvent LightSwitchMgr::CreateNewEvent(AppEvent::AppEventTypes type) +{ + AppEvent aEvent; + aEvent.Type = type; + aEvent.Handler = LightSwitchMgr::AppEventHandler; + LightSwitchMgr * lightSwitch = &LightSwitchMgr::GetInstance(); + aEvent.LightSwitchEvent.Context = lightSwitch; + return aEvent; +} + +void LightSwitchMgr::Timer::Start() +{ + // Starts or restarts the function timer + if (osTimerStart(mHandler, pdMS_TO_TICKS(LONG_PRESS_TIMEOUT)) != osOK) + { + SILABS_LOG("Timer start() failed"); + appError(CHIP_ERROR_INTERNAL); + } + + mIsActive = true; +} + +void LightSwitchMgr::Timer::Timeout() +{ + mIsActive = false; + if (mCallback) + { + mCallback(*this); + } +} + +void LightSwitchMgr::HandleLongPress() +{ + AppEvent event; + event.Handler = AppEventHandler; + LightSwitchMgr * lightSwitch = &LightSwitchMgr::GetInstance(); + event.LightSwitchEvent.Context = lightSwitch; + if (mFunctionButtonPressed) + { + if (!mResetWarning) + { + // Long press button down: Reset warning! + event.Type = AppEvent::kEventType_ResetWarning; + AppTask::GetAppTask().PostEvent(&event); + } + } + else if (mActionButtonPressed) + { + mActionButtonSuppressed = true; + // Long press button up : Trigger Level Control Action + event.Type = AppEvent::kEventType_TriggerLevelControlAction; + AppTask::GetAppTask().PostEvent(&event); + } +} + +void LightSwitchMgr::OnLongPressTimeout(LightSwitchMgr::Timer & timer) +{ + LightSwitchMgr * app = static_cast(timer.mContext); + if (app) + { + app->HandleLongPress(); + } +} + +LightSwitchMgr::Timer::Timer(uint32_t timeoutInMs, Callback callback, void * context) : mCallback(callback), mContext(context) +{ + mHandler = osTimerNew(TimerCallback, // timer callback handler + osTimerOnce, // no timer reload (one-shot timer) + this, // pass the app task obj context + NULL // No osTimerAttr_t to provide. + ); + + if (mHandler == NULL) + { + SILABS_LOG("Timer create failed"); + appError(CHIP_ERROR_INTERNAL); + } +} + +LightSwitchMgr::Timer::~Timer() +{ + if (mHandler) + { + osTimerDelete(mHandler); + mHandler = nullptr; + } +} + +void LightSwitchMgr::Timer::Stop() +{ + mIsActive = false; + if (osTimerStop(mHandler) == osError) + { + SILABS_LOG("Timer stop() failed"); + appError(CHIP_ERROR_INTERNAL); + } +} + +void LightSwitchMgr::Timer::TimerCallback(void * timerCbArg) +{ + Timer * timer = reinterpret_cast(timerCbArg); + if (timer) + { + timer->Timeout(); + } +} + /** * @brief Configures LightSwitchMgr * This function needs to be call before using the LightSwitchMgr @@ -53,6 +165,8 @@ CHIP_ERROR LightSwitchMgr::Init(EndpointId lightSwitchEndpoint, chip::EndpointId mLightSwitchEndpoint = lightSwitchEndpoint; mGenericSwitchEndpoint = genericSwitchEndpoint; + mLongPressTimer = new Timer(LONG_PRESS_TIMEOUT, OnLongPressTimeout, this); + // Configure Bindings CHIP_ERROR error = InitBindingHandler(); if (error != CHIP_NO_ERROR) @@ -94,6 +208,11 @@ void LightSwitchMgr::GenericSwitchOnShortRelease() DeviceLayer::PlatformMgr().ScheduleWork(GenericSwitchWorkerFunction, reinterpret_cast(data)); } +StepModeEnum LightSwitchMgr::getStepMode() +{ + return stepDirection; +} + void LightSwitchMgr::TriggerLightSwitchAction(LightSwitchAction action, bool isGroupCommand) { BindingCommandData * data = Platform::New(); @@ -125,6 +244,22 @@ void LightSwitchMgr::TriggerLightSwitchAction(LightSwitchAction action, bool isG DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); } +void LightSwitchMgr::TriggerLevelControlAction(LevelControl::StepModeEnum stepMode, bool isGroupCommand) +{ + BindingCommandData * data = Platform::New(); + + data->clusterId = chip::app::Clusters::LevelControl::Id; + data->isGroup = isGroupCommand; + data->commandId = LevelControl::Commands::StepWithOnOff::Id; + BindingCommandData::Step stepData{ .stepMode = stepMode, + .stepSize = LightSwitchMgr::stepCommand.stepSize, + .transitionTime = LightSwitchMgr::stepCommand.transitionTime }; + stepData.optionsMask.Set(LightSwitchMgr::stepCommand.optionsMask); + stepData.optionsOverride.Set(LightSwitchMgr::stepCommand.optionsOverride); + data->commandData = stepData; + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); +} + void LightSwitchMgr::GenericSwitchWorkerFunction(intptr_t context) { @@ -159,3 +294,125 @@ void LightSwitchMgr::GenericSwitchWorkerFunction(intptr_t context) Platform::Delete(data); } + +void LightSwitchMgr::ButtonEventHandler(uint8_t button, uint8_t btnAction) +{ + AppEvent event = {}; + if (btnAction == to_underlying(SilabsPlatform::ButtonAction::ButtonPressed)) + { + event = LightSwitchMgr::GetInstance().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonPressed + : AppEvent::kEventType_FunctionButtonPressed); + } + else + { + event = LightSwitchMgr::GetInstance().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonReleased + : AppEvent::kEventType_FunctionButtonReleased); + } + AppTask::GetAppTask().PostEvent(&event); +} + +void LightSwitchMgr::AppEventHandler(AppEvent * aEvent) +{ + LightSwitchMgr * lightSwitch = static_cast(aEvent->LightSwitchEvent.Context); + switch (aEvent->Type) + { + case AppEvent::kEventType_ResetWarning: + lightSwitch->mResetWarning = true; + AppTask::GetAppTask().StartFactoryResetSequence(); + break; + case AppEvent::kEventType_ResetCanceled: + lightSwitch->mResetWarning = false; + AppTask::GetAppTask().CancelFactoryResetSequence(); + break; + case AppEvent::kEventType_FunctionButtonPressed: + lightSwitch->mFunctionButtonPressed = true; + if (lightSwitch->mLongPressTimer) + { + lightSwitch->mLongPressTimer->Start(); + } + if (lightSwitch->mActionButtonPressed) + { + lightSwitch->mActionButtonSuppressed = true; + lightSwitch->stepDirection = + (lightSwitch->stepDirection == StepModeEnum::kUp) ? StepModeEnum::kDown : StepModeEnum::kUp; + ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", + ((lightSwitch->stepDirection == StepModeEnum::kUp) ? "kUp" : "kDown")); + } + break; + case AppEvent::kEventType_FunctionButtonReleased: + lightSwitch->mFunctionButtonPressed = false; + if (lightSwitch->mLongPressTimer) + { + lightSwitch->mLongPressTimer->Stop(); + } + if (lightSwitch->mResetWarning) + { + aEvent->Type = AppEvent::kEventType_ResetCanceled; + AppTask::GetAppTask().PostEvent(aEvent); + } + break; + case AppEvent::kEventType_ActionButtonPressed: + lightSwitch->mActionButtonPressed = true; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + if (lightSwitch->mLongPressTimer) + { + lightSwitch->mLongPressTimer->Start(); + } + if (lightSwitch->mFunctionButtonPressed) + { + lightSwitch->mActionButtonSuppressed = true; + lightSwitch->stepDirection = + (lightSwitch->stepDirection == StepModeEnum::kUp) ? StepModeEnum::kDown : StepModeEnum::kUp; + ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", + ((lightSwitch->stepDirection == StepModeEnum::kUp) ? "kUp" : "kDown")); + } + break; + case AppEvent::kEventType_ActionButtonReleased: + lightSwitch->mActionButtonPressed = false; + if (lightSwitch->mLongPressTimer) + { + lightSwitch->mLongPressTimer->Stop(); + } + if (lightSwitch->mActionButtonSuppressed) + { + lightSwitch->mActionButtonSuppressed = false; + } + else + { + aEvent->Type = AppEvent::kEventType_TriggerToggle; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + } + aEvent->Type = AppEvent::kEventType_ActionButtonReleased; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + break; + case AppEvent::kEventType_TriggerLevelControlAction: + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + default: + break; + } +} + +void LightSwitchMgr::SwitchActionEventHandler(AppEvent * aEvent) +{ + switch (aEvent->Type) + { + case AppEvent::kEventType_ActionButtonPressed: + LightSwitchMgr::GetInstance().GenericSwitchOnInitialPress(); + break; + case AppEvent::kEventType_ActionButtonReleased: + LightSwitchMgr::GetInstance().GenericSwitchOnShortRelease(); + break; + case AppEvent::kEventType_TriggerLevelControlAction: + LightSwitchMgr::GetInstance().TriggerLevelControlAction(LightSwitchMgr::GetInstance().getStepMode()); + break; + case AppEvent::kEventType_TriggerToggle: + LightSwitchMgr::GetInstance().TriggerLightSwitchAction(LightSwitchMgr::LightSwitchAction::Toggle); + break; + default: + break; + } +} diff --git a/examples/light-switch-app/silabs/src/ShellCommands.cpp b/examples/light-switch-app/silabs/src/ShellCommands.cpp index e514a4c9fdecd3..e23e730de88d54 100644 --- a/examples/light-switch-app/silabs/src/ShellCommands.cpp +++ b/examples/light-switch-app/silabs/src/ShellCommands.cpp @@ -38,9 +38,11 @@ using Shell::streamer_printf; Engine sShellSwitchSubCommands; Engine sShellSwitchOnOffSubCommands; +Engine sShellSwitchLevelControlSubCommands; Engine sShellSwitchGroupsSubCommands; Engine sShellSwitchGroupsOnOffSubCommands; +Engine sShellSwitchGroupsLevelControlSubCommands; Engine sShellSwitchBindingSubCommands; @@ -238,6 +240,620 @@ CHIP_ERROR GroupToggleSwitchCommandHandler(int argc, char ** argv) return CHIP_NO_ERROR; } +/******************************************************** + * LevelControl switch shell functions + *********************************************************/ + +CHIP_ERROR LevelControlHelpHandler(int argc, char ** argv) +{ + sShellSwitchLevelControlSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlSwitchCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return LevelControlHelpHandler(argc, argv); + } + + return sShellSwitchLevelControlSubCommands.ExecCommand(argc, argv); +} + +CHIP_ERROR MoveToLevelSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::MoveToLevel{}; + char * endPtr; + if (auto * moveToLevel = std::get_if(&data->commandData)) + { + moveToLevel->level = static_cast(strtol(argv[0], &endPtr, 10)); + moveToLevel->transitionTime = DataModel::Nullable(strtol(argv[1], &endPtr, 10)); + moveToLevel->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + moveToLevel->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR MoveSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Move::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::Move{}; + char * endPtr; + if (auto * move = std::get_if(&data->commandData)) + { + move->moveMode = static_cast(strtol(argv[0], &endPtr, 10)); + move->rate = static_cast>(strtol(argv[1], &endPtr, 10)); + move->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + move->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR StepSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 5) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Step::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Step{}; + if (auto * step = std::get_if(&data->commandData)) + { + step->stepMode = static_cast(strtol(argv[0], &endPtr, 10)); + step->stepSize = static_cast(strtol(argv[1], &endPtr, 10)); + step->transitionTime = DataModel::Nullable(strtol(argv[2], &endPtr, 10)); + step->optionsMask = chip::BitMask(strtol(argv[3], &endPtr, 10)); + step->optionsOverride = chip::BitMask(strtol(argv[4], &endPtr, 10)); + } + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR StopSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 2) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Stop::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Stop{}; + if (auto * stop = std::get_if(&data->commandData)) + { + stop->optionsMask = chip::BitMask(strtol(argv[0], &endPtr, 10)); + stop->optionsOverride = chip::BitMask(strtol(argv[1], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR MoveToLevelWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::MoveToLevel{}; + char * endPtr; + if (auto * moveToLevel = std::get_if(&data->commandData)) + { + moveToLevel->level = static_cast(strtol(argv[0], &endPtr, 10)); + moveToLevel->transitionTime = DataModel::Nullable(strtol(argv[1], &endPtr, 10)); + moveToLevel->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + moveToLevel->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR MoveWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::Move{}; + char * endPtr; + if (auto * move = std::get_if(&data->commandData)) + { + move->moveMode = static_cast(strtol(argv[0], &endPtr, 10)); + move->rate = static_cast>(strtol(argv[1], &endPtr, 10)); + move->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + move->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR StepWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 5) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::StepWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Step{}; + if (auto * step = std::get_if(&data->commandData)) + { + step->stepMode = static_cast(strtol(argv[0], &endPtr, 10)); + step->stepSize = static_cast(strtol(argv[1], &endPtr, 10)); + step->transitionTime = DataModel::Nullable(strtol(argv[2], &endPtr, 10)); + step->optionsMask = chip::BitMask(strtol(argv[3], &endPtr, 10)); + step->optionsOverride = chip::BitMask(strtol(argv[4], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR StopWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 2) + { + return LevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::StopWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Stop{}; + if (auto * stop = std::get_if(&data->commandData)) + { + stop->optionsMask = chip::BitMask(strtol(argv[0], &endPtr, 10)); + stop->optionsOverride = chip::BitMask(strtol(argv[1], &endPtr, 10)); + } + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +#if 0 +/******************************************************** + * LevelControl Read switch shell functions + *********************************************************/ + +CHIP_ERROR LevelControlReadHelpHandler(int argc, char ** argv) +{ + sShellSwitchLevelControlReadSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlRead(int argc, char ** argv) +{ + if (argc == 0) + { + return LevelControlReadHelpHandler(argc, argv); + } + + return sShellSwitchLevelControlReadSubCommands.ExecCommand(argc, argv); +} + +CHIP_ERROR LevelControlReadAttributeList(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::AttributeList::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadCurrentLevel(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::CurrentLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadRemainingTime(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::RemainingTime::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadMinLevel(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::MinLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadMaxLevel(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::MaxLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadCurrentFrequency(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::CurrentFrequency::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadMinFrequency(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::MinFrequency::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadMaxFrequency(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::MaxFrequency::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadOptions(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::Options::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadOnOffTransitionTime(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::OnOffTransitionTime::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadOnLevel(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::OnLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadOnTransitionTime(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::OnTransitionTime::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadOffTransitionTime(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::OffTransitionTime::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadDefaultMoveRate(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::DefaultMoveRate::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LevelControlReadStartUpCurrentLevel(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->attributeId = Clusters::LevelControl::Attributes::StartUpCurrentLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->isReadAttribute = true; + ChipLogProgress(NotSpecified, "Read cluster=0x%x, attribute=0x%08x", data->clusterId, data->attributeId); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +#endif // commenting the read functions + +/******************************************************** + * Groups LevelControl switch shell functions + *********************************************************/ + +CHIP_ERROR GroupsLevelControlHelpHandler(int argc, char ** argv) +{ + sShellSwitchGroupsLevelControlSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsLevelControlSwitchCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + return sShellSwitchGroupsLevelControlSubCommands.ExecCommand(argc, argv); +} + +CHIP_ERROR GroupsMoveToLevelSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevel::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::MoveToLevel{}; + char * endPtr; + if (auto * moveToLevel = std::get_if(&data->commandData)) + { + moveToLevel->level = static_cast(strtol(argv[0], &endPtr, 10)); + moveToLevel->transitionTime = DataModel::Nullable(strtol(argv[1], &endPtr, 10)); + moveToLevel->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + moveToLevel->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsMoveSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Move::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::Move{}; + char * endPtr; + if (auto * move = std::get_if(&data->commandData)) + { + move->moveMode = static_cast(strtol(argv[0], &endPtr, 10)); + move->rate = static_cast>(strtol(argv[1], &endPtr, 10)); + move->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + move->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsStepSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 5) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Step::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Step{}; + if (auto * step = std::get_if(&data->commandData)) + { + step->stepMode = static_cast(strtol(argv[0], &endPtr, 10)); + step->stepSize = static_cast(strtol(argv[1], &endPtr, 10)); + step->transitionTime = DataModel::Nullable(strtol(argv[2], &endPtr, 10)); + step->optionsMask = chip::BitMask(strtol(argv[3], &endPtr, 10)); + step->optionsOverride = chip::BitMask(strtol(argv[4], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsStopSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 2) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::Stop::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Stop{}; + if (auto * stop = std::get_if(&data->commandData)) + { + stop->optionsMask = chip::BitMask(strtol(argv[0], &endPtr, 10)); + stop->optionsOverride = chip::BitMask(strtol(argv[1], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsMoveToLevelWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::MoveToLevel{}; + char * endPtr; + if (auto * moveToLevel = std::get_if(&data->commandData)) + { + moveToLevel->level = static_cast(strtol(argv[0], &endPtr, 10)); + moveToLevel->transitionTime = DataModel::Nullable(strtol(argv[1], &endPtr, 10)); + moveToLevel->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + moveToLevel->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsMoveWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 4) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->commandData = BindingCommandData::Move{}; + char * endPtr; + if (auto * move = std::get_if(&data->commandData)) + { + move->moveMode = static_cast(strtol(argv[0], &endPtr, 10)); + move->rate = static_cast>(strtol(argv[1], &endPtr, 10)); + move->optionsMask = chip::BitMask(strtol(argv[2], &endPtr, 10)); + move->optionsOverride = chip::BitMask(strtol(argv[3], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsStepWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 5) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::StepWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Step{}; + if (auto * step = std::get_if(&data->commandData)) + { + step->stepMode = static_cast(strtol(argv[0], &endPtr, 10)); + step->stepSize = static_cast(strtol(argv[1], &endPtr, 10)); + step->transitionTime = DataModel::Nullable(strtol(argv[2], &endPtr, 10)); + step->optionsMask = chip::BitMask(strtol(argv[3], &endPtr, 10)); + step->optionsOverride = chip::BitMask(strtol(argv[4], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR GroupsStopWithOnOffSwitchCommandHandler(int argc, char ** argv) +{ + if (argc != 2) + { + return GroupsLevelControlHelpHandler(argc, argv); + } + + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::StopWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + char * endPtr; + data->commandData = BindingCommandData::Stop{}; + if (auto * stop = std::get_if(&data->commandData)) + { + stop->optionsMask = chip::BitMask(strtol(argv[0], &endPtr, 10)); + stop->optionsOverride = chip::BitMask(strtol(argv[1], &endPtr, 10)); + } + data->isGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + /** * @brief configures switch matter shell */ @@ -246,6 +862,7 @@ void RegisterSwitchCommands() static const shell_command_t sSwitchSubCommands[] = { { &SwitchHelpHandler, "help", "Usage: switch " }, { &OnOffSwitchCommandHandler, "onoff", " Usage: switch onoff " }, + { &LevelControlSwitchCommandHandler, "levelcontrol", " Usage: switch levelcontrol " }, { &GroupsSwitchCommandHandler, "groups", "Usage: switch groups " }, { &BindingSwitchCommandHandler, "binding", "Usage: switch binding " } }; @@ -257,6 +874,25 @@ void RegisterSwitchCommands() { &ToggleSwitchCommandHandler, "toggle", "Sends toggle command to bound lighting app" } }; + static const shell_command_t sSwitchLevelControlSubCommands[] = { + { &LevelControlHelpHandler, "help", "Usage: switch levelcontrol " }, + { &MoveToLevelSwitchCommandHandler, "move-to-level", + "Usage: switch levelcontrol move-to-level " }, + { &MoveSwitchCommandHandler, "move", "Usage: switch levelcontrol move " }, + { &StepSwitchCommandHandler, "step", + "Usage: switch levelcontrol step " }, + { &StopSwitchCommandHandler, "stop", "step Usage: switch levelcontrol stop " }, + { &MoveToLevelWithOnOffSwitchCommandHandler, "move-to-level-with-on-off", + "Usage: switch levelcontrol move-with-to-level-with-on-off " }, + { &MoveWithOnOffSwitchCommandHandler, "move-with-on-off", + "Usage: switch levelcontrol move-with-on-off " }, + { &StepWithOnOffSwitchCommandHandler, "step-with-on-off", + "Usage: switch levelcontrol step-with-on-off " + "" }, + { &StopWithOnOffSwitchCommandHandler, "stop-with-on-off", + "Usage: switch levelcontrol stop-with-on-off " }, + }; + static const shell_command_t sSwitchGroupsSubCommands[] = { { &GroupsHelpHandler, "help", "Usage: switch groups " }, { &GroupsOnOffSwitchCommandHandler, "onoff", "Usage: switch groups onoff " } }; @@ -268,6 +904,27 @@ void RegisterSwitchCommands() { &GroupToggleSwitchCommandHandler, "toggle", "Sends toggle command to group" } }; + static const shell_command_t sSwitchGroupsLevelControlSubCommands[] = { + { &GroupsLevelControlHelpHandler, "help", "Usage: switch groups levelcontrol " }, + { &GroupsMoveToLevelSwitchCommandHandler, "move-to-level", + "Usage: switch groups levelcontrol move-to-level " }, + { &GroupsMoveSwitchCommandHandler, "move", + "Usage: switch groups levelcontrol move " }, + { &GroupsStepSwitchCommandHandler, "step", + "Usage: switch groups levelcontrol step " }, + { &GroupsStopSwitchCommandHandler, "stop", "step Usage: switch groups levelcontrol stop " }, + { &GroupsMoveToLevelWithOnOffSwitchCommandHandler, "move-to-level-with-on-off", + "Usage: switch groups levelcontrol move-with-to-level-with-on-off " + "" }, + { &GroupsMoveWithOnOffSwitchCommandHandler, "move-with-on-off", + "Usage: switch groups levelcontrol move-with-on-off " }, + { &GroupsStepWithOnOffSwitchCommandHandler, "step-with-on-off", + "Usage: switch groups levelcontrol step-with-on-off " + "" }, + { &GroupsStopWithOnOffSwitchCommandHandler, "stop-with-on-off", + "Usage: switch groups levelcontrol stop-with-on-off " }, + }; + static const shell_command_t sSwitchBindingSubCommands[] = { { &BindingHelpHandler, "help", "Usage: switch binding " }, { &BindingGroupBindCommandHandler, "group", "Usage: switch binding group " }, @@ -279,7 +936,11 @@ void RegisterSwitchCommands() sShellSwitchGroupsOnOffSubCommands.RegisterCommands(sSwitchGroupsOnOffSubCommands, MATTER_ARRAY_SIZE(sSwitchGroupsOnOffSubCommands)); + sShellSwitchGroupsLevelControlSubCommands.RegisterCommands(sSwitchGroupsLevelControlSubCommands, + MATTER_ARRAY_SIZE(sSwitchGroupsLevelControlSubCommands)); sShellSwitchOnOffSubCommands.RegisterCommands(sSwitchOnOffSubCommands, MATTER_ARRAY_SIZE(sSwitchOnOffSubCommands)); + sShellSwitchLevelControlSubCommands.RegisterCommands(sSwitchLevelControlSubCommands, + MATTER_ARRAY_SIZE(sSwitchLevelControlSubCommands)); sShellSwitchGroupsSubCommands.RegisterCommands(sSwitchGroupsSubCommands, MATTER_ARRAY_SIZE(sSwitchGroupsSubCommands)); sShellSwitchBindingSubCommands.RegisterCommands(sSwitchBindingSubCommands, MATTER_ARRAY_SIZE(sSwitchBindingSubCommands)); sShellSwitchSubCommands.RegisterCommands(sSwitchSubCommands, MATTER_ARRAY_SIZE(sSwitchSubCommands));