/* * * Copyright (c) 2022 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. */ #include "BindingHandler.h" #include "ColorControlCommands.h" #include "IdentifyCommand.h" #include "LevelControlCommands.h" #include "OnOffCommands.h" #include "ThermostatCommands.h" #include "app/clusters/bindings/BindingManager.h" #include "app/server/Server.h" #include "controller/InvokeInteraction.h" #include "controller/ReadInteraction.h" #include "platform/CHIPDeviceLayer.h" #include #include #if CONFIG_ENABLE_CHIP_SHELL #include "lib/shell/Engine.h" #include "lib/shell/commands/Help.h" #endif // ENABLE_CHIP_SHELL using namespace chip; using namespace chip::app; #if CONFIG_ENABLE_CHIP_SHELL using Shell::Engine; using Shell::shell_command_t; using Shell::streamer_get; using Shell::streamer_printf; Engine sShellSwitchSubCommands; Engine sShellSwitchGroupsSubCommands; Engine sShellSwitchBindingSubCommands; #endif // defined(ENABLE_CHIP_SHELL) namespace { void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context) { VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null")); BindingCommandData * data = static_cast(context); if (data->isReadAttribute) { // It should always enter here if isReadAttribute is true if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) { switch (data->clusterId) { case Clusters::Identify::Id: ProcessIdentifyUnicastBindingRead(data, binding, peer_device); break; case Clusters::OnOff::Id: ProcessOnOffUnicastBindingRead(data, binding, peer_device); break; case Clusters::LevelControl::Id: ProcessLevelControlUnicastBindingRead(data, binding, peer_device); break; case Clusters::ColorControl::Id: ProcessColorControlUnicastBindingRead(data, binding, peer_device); break; case Clusters::Thermostat::Id: ProcessThermostatUnicastBindingRead(data, binding, peer_device); break; } } } else { if (binding.type == MATTER_MULTICAST_BINDING && data->isGroup) { switch (data->clusterId) { case Clusters::Identify::Id: ProcessIdentifyGroupBindingCommand(data, binding); break; case Clusters::OnOff::Id: ProcessOnOffGroupBindingCommand(data, binding); break; case Clusters::LevelControl::Id: ProcessColorControlGroupBindingCommand(data, binding); break; case Clusters::ColorControl::Id: ProcessColorControlGroupBindingCommand(data, binding); break; case Clusters::Thermostat::Id: ProcessThermostatGroupBindingCommand(data, binding); break; } } else if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) { switch (data->clusterId) { case Clusters::Identify::Id: ProcessIdentifyUnicastBindingCommand(data, binding, peer_device); break; case Clusters::OnOff::Id: ProcessOnOffUnicastBindingCommand(data, binding, peer_device); break; case Clusters::LevelControl::Id: ProcessLevelControlUnicastBindingCommand(data, binding, peer_device); break; case Clusters::ColorControl::Id: ProcessColorControlUnicastBindingCommand(data, binding, peer_device); break; case Clusters::Thermostat::Id: ProcessThermostatUnicastBindingCommand(data, binding, peer_device); break; } } } } void LightSwitchContextReleaseHandler(void * context) { VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "Invalid context for Light switch context release handler")); Platform::Delete(static_cast(context)); } void InitBindingHandlerInternal(intptr_t arg) { auto & server = chip::Server::GetInstance(); chip::BindingManager::GetInstance().Init( { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }); chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler); chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler); } #if CONFIG_ENABLE_CHIP_SHELL /******************************************************** * Switch shell functions *********************************************************/ CHIP_ERROR SwitchHelpHandler(int argc, char ** argv) { sShellSwitchSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); return CHIP_NO_ERROR; } CHIP_ERROR SwitchCommandHandler(int argc, char ** argv) { if (argc == 0) { return SwitchHelpHandler(argc, argv); } return sShellSwitchSubCommands.ExecCommand(argc, argv); } /******************************************************** * bind switch shell functions *********************************************************/ CHIP_ERROR BindingHelpHandler(int argc, char ** argv) { sShellSwitchBindingSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); return CHIP_NO_ERROR; } CHIP_ERROR BindingSwitchCommandHandler(int argc, char ** argv) { if (argc == 0) { return BindingHelpHandler(argc, argv); } return sShellSwitchBindingSubCommands.ExecCommand(argc, argv); } CHIP_ERROR BindingGroupBindCommandHandler(int argc, char ** argv) { VerifyOrReturnError(argc == 2, CHIP_ERROR_INVALID_ARGUMENT); EmberBindingTableEntry * entry = Platform::New(); entry->type = MATTER_MULTICAST_BINDING; entry->fabricIndex = atoi(argv[0]); entry->groupId = atoi(argv[1]); entry->local = 1; // Hardcoded to endpoint 1 for now entry->clusterId.emplace(6); // Hardcoded to OnOff cluster for now DeviceLayer::PlatformMgr().ScheduleWork(BindingWorkerFunction, reinterpret_cast(entry)); return CHIP_NO_ERROR; } CHIP_ERROR BindingUnicastBindCommandHandler(int argc, char ** argv) { VerifyOrReturnError(argc == 3, CHIP_ERROR_INVALID_ARGUMENT); EmberBindingTableEntry * entry = Platform::New(); entry->type = MATTER_UNICAST_BINDING; entry->fabricIndex = atoi(argv[0]); entry->nodeId = atoi(argv[1]); entry->local = 1; // Hardcoded to endpoint 1 for now entry->remote = atoi(argv[2]); entry->clusterId.emplace(6); // Hardcode to OnOff cluster for now DeviceLayer::PlatformMgr().ScheduleWork(BindingWorkerFunction, reinterpret_cast(entry)); return CHIP_NO_ERROR; } /******************************************************** * Groups switch shell functions *********************************************************/ CHIP_ERROR GroupsHelpHandler(int argc, char ** argv) { sShellSwitchGroupsSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); return CHIP_NO_ERROR; } CHIP_ERROR GroupsSwitchCommandHandler(int argc, char ** argv) { if (argc == 0) { return GroupsHelpHandler(argc, argv); } return sShellSwitchGroupsSubCommands.ExecCommand(argc, argv); } /** * @brief configures switch matter shell * */ static void RegisterSwitchCommands() { static const shell_command_t sSwitchSubCommands[] = { { &SwitchHelpHandler, "help", "Usage: switch " }, { &IdentifySwitchCommandHandler, "identify", " Usage: switch identify " }, { &OnOffSwitchCommandHandler, "onoff", " Usage: switch onoff " }, { &LevelControlSwitchCommandHandler, "levelcontrol", " Usage: switch levlecontrol " }, { &ColorControlSwitchCommandHandler, "colorcontrol", " Usage: switch colorcontrol " }, { &ThermostatSwitchCommandHandler, "thermostat", " Usage: switch thermostat " }, { &GroupsSwitchCommandHandler, "groups", "Usage: switch groups " }, { &BindingSwitchCommandHandler, "binding", "Usage: switch binding " } }; static const shell_command_t sSwitchIdentifySubCommands[] = { { &IdentifyHelpHandler, "help", "Usage: switch identify " }, { &IdentifyCommandHandler, "identify", "identify Usage: switch identify identify" }, { &TriggerEffectSwitchCommandHandler, "triggereffect", "triggereffect Usage: switch identify triggereffect" }, { &IdentifyRead, "read", "Usage : switch identify read " } }; static const shell_command_t sSwitchIdentifyReadSubCommands[] = { { &IdentifyReadHelpHandler, "help", "Usage : switch identify read " }, { &IdentifyReadAttributeList, "attlist", "Read attribute list" }, { &IdentifyReadIdentifyTime, "identifytime", "Read identifytime attribute" }, { &IdentifyReadIdentifyType, "identifytype", "Read identifytype attribute" }, }; static const shell_command_t sSwitchOnOffSubCommands[] = { { &OnOffHelpHandler, "help", "Usage: switch ononff " }, { &OnSwitchCommandHandler, "on", "on Usage: switch onoff on" }, { &OffSwitchCommandHandler, "off", "off Usage: switch onoff off" }, { &ToggleSwitchCommandHandler, "toggle", "toggle Usage: switch onoff toggle" }, { &OffWithEffectSwitchCommandHandler, "offWE", "off-with-effect Usage: switch onoff offWE " }, { &OnWithRecallGlobalSceneSwitchCommandHandler, "onWRGS", "on-with-recall-global-scene Usage: switch onoff onWRGS" }, { &OnWithTimedOffSwitchCommandHandler, "onWTO", "on-with-timed-off Usage: switch onoff onWTO " }, { &OnOffRead, "read", "Usage : switch onoff read " } }; static const shell_command_t sSwitchOnOffReadSubCommands[] = { { &OnOffReadHelpHandler, "help", "Usage : switch ononff read " }, { &OnOffReadAttributeList, "attlist", "Read attribute list" }, { &OnOffReadOnOff, "onoff", "Read onoff attribute" }, { &OnOffReadGlobalSceneControl, "GSC", "Read GlobalSceneControl attribute" }, { &OnOffReadOnTime, "ontime", "Read ontime attribute" }, { &OnOffReadOffWaitTime, "offwaittime", "Read offwaittime attribute" }, { &OnOffReadStartUpOnOff, "SOO", "Read startuponoff attribute" }, }; static const shell_command_t sSwitchLevelControlSubCommands[] = { { &LevelControlHelpHandler, "help", "Usage: switch levelcontrol " }, { &MoveToLevelSwitchCommandHandler, "movetolevel", "movetolevel Usage: switch levelcontrol movetolevel " }, { &MoveSwitchCommandHandler, "move", "move Usage: switch levelcontrol move " }, { &StepSwitchCommandHandler, "step", "step Usage: switch levelcontrol step " }, { &StopSwitchCommandHandler, "stop", "step Usage: switch levelcontrol stop " }, { &MoveToLevelWithOnOffSwitchCommandHandler, "MTLWOO", "movetolevelwithonoff Usage: switch levelcontrol MTLWOO " }, { &MoveWithOnOffSwitchCommandHandler, "MWOO", "movewithonoff Usage: switch levelcontrol MWOO " }, { &StepWithOnOffSwitchCommandHandler, "stepWOO", "stepwithonoff Usage: switch levelcontrol stepWOO " "" }, { &StopWithOnOffSwitchCommandHandler, "stopWOO", "stopwithonoff Usage: switch levelcontrol stopWOO " }, { &LevelControlRead, "read", "Usage : switch levelcontrol read " } }; static const shell_command_t sSwitchLevelControlReadSubCommands[] = { { &LevelControlReadHelpHandler, "help", "Usage : switch levelcontrol read " }, { &LevelControlReadAttributeList, "attlist", "Read attribute list" }, { &LevelControlReadCurrentLevel, "currentlevel", "Read currentlevel attribute" }, { &LevelControlReadRemainingTime, "remainingtime", "Read remainingtime attribute" }, { &LevelControlReadMinLevel, "minlevel", "Read minlevel attribute" }, { &LevelControlReadMaxLevel, "maxlevel", "Read maxlevel attribute" }, { &LevelControlReadCurrentFrequency, "currentfrequency", "Read currentfrequency attribute" }, { &LevelControlReadMinFrequency, "minfrequency", "Read minfrequency attribute" }, { &LevelControlReadMaxFrequency, "maxfrequency", "Read maxfrequency attribute" }, { &LevelControlReadOptions, "options", "Read options attribute" }, { &LevelControlReadOnOffTransitionTime, "OOTT", "Read onofftransitiontime attribute" }, { &LevelControlReadOnLevel, "onlevel", "Read onlevel attribute" }, { &LevelControlReadOnTransitionTime, "OnTT", "Read ontransitiontime attribute" }, { &LevelControlReadOffTransitionTime, "OffTT", "Read offtransitiontime attribute" }, { &LevelControlReadDefaultMoveRate, "DMR", "Read defaultmoverate attribute" }, { &LevelControlReadStartUpCurrentLevel, "SUCL", "Read startupcurrentlevel attribute" }, }; static const shell_command_t sSwitchColorControlSubCommands[] = { { &ColorControlHelpHandler, "help", "Usage: switch colorcontrol " }, { &MoveToHueCommandHandler, "movetohue", "movetohue Usage: switch colorcontrol movetohue " }, { &MoveHueCommandHandler, "movehue", "movehue Usage: switch colorcontrol movehue " }, { &StepHueCommandHandler, "stephue", "stephue Usage: switch colorcontrol stephue " }, { &MoveToSaturationCommandHandler, "movetosat", "movetosaturation Usage: switch colorcontrol movetosat " }, { &MoveSaturationCommandHandler, "movesat", "movesaturation Usage: switch colorcontrol movesat " }, { &StepSaturationCommandHandler, "stepsat", "stepsaturation Usage: switch colorcontrol stepsat " "" }, { &MoveToHueAndSaturationCommandHandler, "movetoHS", "movetohueandsaturation Usage: switch colorcontrol movetoHS " "" }, { &MoveToColorCommandHandler, "movetocolor", "movetocolor Usage: switch colorcontrol movetocolor " }, { &MoveColorCommandHandler, "movecolor", "movecolor Usage: switch colorcontrol movecolor " }, { &StepColorCommandHandler, "stepcolor", "stepcolor Usage: switch colorcontrol stepcolor " }, { &MoveToColorTemperatureCommandHandler, "movetoCT", "movetocolortemperature Usage: switch colorcontrol movetoCT " "" }, { &EnhancedMoveToHueCommandHandler, "Emovetohue", "enhancedmovetohue Usage: switch colorcontrol Emovetohue " "" }, { &EnhancedMoveHueCommandHandler, "Emovehue", "enhancedmovehue Usage: switch colorcontrol Emovehue " }, { &EnhancedStepHueCommandHandler, "Estephue", "enhancedstephue Usage: switch colorcontrol Estephue " "" }, { &EnhancedMoveToHueAndSaturationCommandHandler, "EmovetoHS", "enhancedmovetohueandsaturation Usage: switch colorcontrol EmovetoHS " " " }, { &ColorLoopSetCommandHandler, "colorloopset", "colorloopset Usage: switch colorcontrol colorloopset