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 595b0d8f83..3101a57697 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 @@ -4400,29 +4400,29 @@ }, { "id": 2, - "name": "MA-onofflightswitch", + "name": "MA-dimmablelight", "deviceTypeRef": { - "code": 259, + "code": 257, "profileId": 259, - "label": "MA-onofflightswitch", - "name": "MA-onofflightswitch" + "label": "MA-dimmablelight", + "name": "MA-dimmablelight" }, "deviceTypes": [ { - "code": 259, + "code": 257, "profileId": 259, - "label": "MA-onofflightswitch", - "name": "MA-onofflightswitch" + "label": "MA-dimmablelight", + "name": "MA-dimmablelight" } ], "deviceVersions": [ 1 ], "deviceIdentifiers": [ - 259 + 257 ], - "deviceTypeName": "MA-onofflightswitch", - "deviceTypeCode": 259, + "deviceTypeName": "MA-dimmablelight", + "deviceTypeCode": 257, "deviceTypeProfileId": 259, "clusters": [ { @@ -4733,6 +4733,24 @@ } ] }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "MoveToLevelWithOnOff", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, { "name": "Descriptor", "code": 29, @@ -5633,7 +5651,7 @@ "parentEndpointIdentifier": null }, { - "endpointTypeName": "MA-onofflightswitch", + "endpointTypeName": "MA-dimmablelight", "endpointTypeIndex": 1, "profileId": 259, "endpointId": 1, diff --git a/examples/light-switch-app/silabs/include/BindingHandler.h b/examples/light-switch-app/silabs/include/BindingHandler.h index aed08be25e..8a579499cd 100644 --- a/examples/light-switch-app/silabs/include/BindingHandler.h +++ b/examples/light-switch-app/silabs/include/BindingHandler.h @@ -30,4 +30,11 @@ struct BindingCommandData chip::CommandId commandId; chip::ClusterId clusterId; bool isGroup = false; + union + { + struct + { + uint8_t level; + } LevelData; + }; }; diff --git a/examples/light-switch-app/silabs/include/LightSwitchMgr.h b/examples/light-switch-app/silabs/include/LightSwitchMgr.h index adfe75fda9..3684d2bcdd 100644 --- a/examples/light-switch-app/silabs/include/LightSwitchMgr.h +++ b/examples/light-switch-app/silabs/include/LightSwitchMgr.h @@ -23,6 +23,9 @@ #include #include +#define MIN_LEVEL 0 +#define MAX_LEVEL 254 + class LightSwitchMgr { public: @@ -45,6 +48,8 @@ class LightSwitchMgr void GenericSwitchOnShortRelease(); void TriggerLightSwitchAction(LightSwitchAction action, bool isGroupCommand = false); + void TriggerLevelControlAction(uint8_t level, bool isGroupCommand = false); + uint8_t currentLevel; static LightSwitchMgr & GetInstance() { return sSwitch; } diff --git a/examples/light-switch-app/silabs/src/AppTask.cpp b/examples/light-switch-app/silabs/src/AppTask.cpp index 140a99136d..3fb600e6db 100644 --- a/examples/light-switch-app/silabs/src/AppTask.cpp +++ b/examples/light-switch-app/silabs/src/AppTask.cpp @@ -143,6 +143,8 @@ void AppTask::SwitchActionEventHandler(AppEvent * aEvent) mCurrentButtonState ? LightSwitchMgr::LightSwitchAction::On : LightSwitchMgr::LightSwitchAction::Off; LightSwitchMgr::GetInstance().TriggerLightSwitchAction(action); + LightSwitchMgr::GetInstance().currentLevel = mCurrentButtonState ? MAX_LEVEL : MIN_LEVEL; + LightSwitchMgr::GetInstance().TriggerLevelControlAction(LightSwitchMgr::GetInstance().currentLevel); LightSwitchMgr::GetInstance().GenericSwitchOnInitialPress(); #ifdef DISPLAY_ENABLED diff --git a/examples/light-switch-app/silabs/src/BindingHandler.cpp b/examples/light-switch-app/silabs/src/BindingHandler.cpp index 56f7c306f9..62fab2a907 100644 --- a/examples/light-switch-app/silabs/src/BindingHandler.cpp +++ b/examples/light-switch-app/silabs/src/BindingHandler.cpp @@ -35,11 +35,11 @@ void ProcessOnOffUnicastBindingCommand(CommandId commandId, const EmberBindingTa Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle) { auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { - ChipLogProgress(NotSpecified, "OnOff command succeeds"); + ChipLogProgress(AppServer, "OnOff command succeeds"); }; auto onFailure = [](CHIP_ERROR error) { - ChipLogError(NotSpecified, "OnOff command failed: %" CHIP_ERROR_FORMAT, error.Format()); + ChipLogError(AppServer, "OnOff command failed: %" CHIP_ERROR_FORMAT, error.Format()); }; switch (commandId) @@ -61,6 +61,28 @@ void ProcessOnOffUnicastBindingCommand(CommandId commandId, const EmberBindingTa } } +void ProcessLevelControlUnicastBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding, + Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, + BindingCommandData * data) +{ + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + ChipLogProgress(AppServer, "LevelControl command succeeds"); + }; + + auto onFailure = [](CHIP_ERROR error) { + ChipLogError(AppServer, "LevelControl command failed: %" CHIP_ERROR_FORMAT, error.Format()); + }; + + switch (commandId) + { + case Clusters::LevelControl::Commands::Move::Id: + Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Type moveCommand; + moveCommand.level = data->LevelData.level; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, moveCommand, onSuccess, onFailure); + break; + } +} + void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding) { Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); @@ -85,9 +107,23 @@ void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTabl } } +void ProcessLevelControlGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding, BindingCommandData * data) +{ + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + + switch (commandId) + { + case Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id: + Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Type moveCommand; + moveCommand.level = data->LevelData.level; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveCommand); + break; + } +} + void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context) { - VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null")); + VerifyOrReturn(context != nullptr, ChipLogError(AppServer, "OnDeviceConnectedFn: context is null")); BindingCommandData * data = static_cast(context); if (binding.type == MATTER_MULTICAST_BINDING && data->isGroup) @@ -97,6 +133,9 @@ void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, Operation case Clusters::OnOff::Id: ProcessOnOffGroupBindingCommand(data->commandId, binding); break; + case Clusters::LevelControl::Id: + ProcessLevelControlGroupBindingCommand(data->commandId, binding, data); + break; } } else if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) @@ -108,13 +147,18 @@ void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, Operation ProcessOnOffUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value()); break; + case Clusters::LevelControl::Id: + VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady()); + ProcessLevelControlUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(), + peer_device->GetSecureSession().Value(), data); + break; } } } void LightSwitchContextReleaseHandler(void * context) { - VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "LightSwitchContextReleaseHandler: context is null")); + VerifyOrReturn(context != nullptr, ChipLogError(AppServer, "LightSwitchContextReleaseHandler: context is null")); Platform::Delete(static_cast(context)); } @@ -135,15 +179,17 @@ void InitBindingHandlerInternal(intptr_t arg) void SwitchWorkerFunction(intptr_t context) { - VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "SwitchWorkerFunction - Invalid work data")); + VerifyOrReturn(context != 0, ChipLogError(AppServer, "SwitchWorkerFunction - Invalid work data")); BindingCommandData * data = reinterpret_cast(context); BindingManager::GetInstance().NotifyBoundClusterChanged(data->localEndpointId, data->clusterId, static_cast(data)); + + Platform::Delete(data); } void BindingWorkerFunction(intptr_t context) { - VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingWorkerFunction - Invalid work data")); + VerifyOrReturn(context != 0, ChipLogError(AppServer, "BindingWorkerFunction - Invalid work data")); EmberBindingTableEntry * entry = reinterpret_cast(context); AddBindingEntry(*entry); diff --git a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp index b33ac42630..3322517afc 100644 --- a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp +++ b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp @@ -125,6 +125,20 @@ void LightSwitchMgr::TriggerLightSwitchAction(LightSwitchAction action, bool isG DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); } +void LightSwitchMgr::TriggerLevelControlAction(uint8_t level, bool isGroupCommand) +{ + BindingCommandData * data = Platform::New(); + + data->clusterId = chip::app::Clusters::LevelControl::Id; + data->isGroup = isGroupCommand; + + data->commandId = chip::app::Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id; + data->LevelData.level = level; + + ChipLogProgress(DeviceLayer, "Level is - %d", data->LevelData.level); + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); +} + void LightSwitchMgr::GenericSwitchWorkerFunction(intptr_t context) { diff --git a/examples/light-switch-app/silabs/src/ShellCommands.cpp b/examples/light-switch-app/silabs/src/ShellCommands.cpp index 167453906e..8d8e3513d9 100644 --- a/examples/light-switch-app/silabs/src/ShellCommands.cpp +++ b/examples/light-switch-app/silabs/src/ShellCommands.cpp @@ -20,6 +20,7 @@ #include "ShellCommands.h" #include "BindingHandler.h" +#include "LightSwitchMgr.h" #include #include @@ -38,9 +39,11 @@ using Shell::streamer_printf; Engine sShellSwitchSubCommands; Engine sShellSwitchOnOffSubCommands; +Engine sShellSwitchLevelControlSubCommands; Engine sShellSwitchGroupsSubCommands; Engine sShellSwitchGroupsOnOffSubCommands; +Engine sShellSwitchGroupsLevelControlSubCommands; Engine sShellSwitchBindingSubCommands; @@ -114,6 +117,45 @@ CHIP_ERROR ToggleSwitchCommandHandler(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 MoveToLevelCommandHandler(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->LevelData.level = atoi(argv[0]); + if (LightSwitchMgr::GetInstance().currentLevel > MIN_LEVEL && data->LevelData.level == MIN_LEVEL) + { + OffSwitchCommandHandler(0,NULL); + } + if (LightSwitchMgr::GetInstance().currentLevel == MIN_LEVEL && data->LevelData.level > MIN_LEVEL) + { + OnSwitchCommandHandler(0,NULL); + } + LightSwitchMgr::GetInstance().currentLevel = data->LevelData.level; + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + /******************************************************** * bind switch shell functions *********************************************************/ @@ -238,6 +280,47 @@ CHIP_ERROR GroupToggleSwitchCommandHandler(int argc, char ** argv) return CHIP_NO_ERROR; } +/******************************************************** + * 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 GroupLevelControlSwitchCommandHandler(int argc, char ** argv) +{ + BindingCommandData * data = Platform::New(); + data->commandId = Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id; + data->clusterId = Clusters::LevelControl::Id; + data->LevelData.level = atoi(argv[0]); + data->isGroup = true; + + if (LightSwitchMgr::GetInstance().currentLevel > MIN_LEVEL && data->LevelData.level == MIN_LEVEL) + { + OffSwitchCommandHandler(0,NULL); + } + if (LightSwitchMgr::GetInstance().currentLevel == MIN_LEVEL && data->LevelData.level > MIN_LEVEL) + { + OnSwitchCommandHandler(0,NULL); + } + LightSwitchMgr::GetInstance().currentLevel = data->LevelData.level; + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + /** * @brief configures switch matter shell */ @@ -246,6 +329,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 +341,11 @@ void RegisterSwitchCommands() { &ToggleSwitchCommandHandler, "toggle", "Sends toggle command to bound lighting app" } }; + static const shell_command_t sSwitchLevelControlSubCommands[] = { + { &LevelControlHelpHandler, "help", "Usage : switch levelcontrol " }, + { &MoveToLevelCommandHandler, "move-to-level-with-on-off", "Sends move-to-level command to bound lighting app" }, + }; + static const shell_command_t sSwitchGroupsSubCommands[] = { { &GroupsHelpHandler, "help", "Usage: switch groups " }, { &GroupsOnOffSwitchCommandHandler, "onoff", "Usage: switch groups onoff " } }; @@ -268,6 +357,11 @@ void RegisterSwitchCommands() { &GroupToggleSwitchCommandHandler, "toggle", "Sends toggle command to group" } }; + static const shell_command_t sSwitchGroupsLevelControlSubCommands[] = { + { &GroupsLevelControlHelpHandler, "help", "Usage: switch groups levelcontrol " }, + { &GroupLevelControlSwitchCommandHandler, "move-to-level-with-on-off", "Sends move-to-level command to bound group" }, + }; + static const shell_command_t sSwitchBindingSubCommands[] = { { &BindingHelpHandler, "help", "Usage: switch binding " }, { &BindingGroupBindCommandHandler, "group", "Usage: switch binding group " }, @@ -278,7 +372,9 @@ void RegisterSwitchCommands() "Light-switch commands. Usage: switch " }; sShellSwitchGroupsOnOffSubCommands.RegisterCommands(sSwitchGroupsOnOffSubCommands, ArraySize(sSwitchGroupsOnOffSubCommands)); + sShellSwitchGroupsLevelControlSubCommands.RegisterCommands(sSwitchGroupsLevelControlSubCommands, ArraySize(sSwitchGroupsLevelControlSubCommands)); sShellSwitchOnOffSubCommands.RegisterCommands(sSwitchOnOffSubCommands, ArraySize(sSwitchOnOffSubCommands)); + sShellSwitchLevelControlSubCommands.RegisterCommands(sSwitchLevelControlSubCommands, ArraySize(sSwitchLevelControlSubCommands)); sShellSwitchGroupsSubCommands.RegisterCommands(sSwitchGroupsSubCommands, ArraySize(sSwitchGroupsSubCommands)); sShellSwitchBindingSubCommands.RegisterCommands(sSwitchBindingSubCommands, ArraySize(sSwitchBindingSubCommands)); sShellSwitchSubCommands.RegisterCommands(sSwitchSubCommands, ArraySize(sSwitchSubCommands));