blob: e90bd79f1e36c6f6dae59eb79f4473fda1867722 [file] [log] [blame]
/*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app-common/zap-generated/cluster-objects.h>
#include <app/reporting/reporting.h>
#include <app/server-cluster/DefaultServerCluster.h>
#include <lib/support/TimerDelegate.h>
namespace chip::app::Clusters {
class IdentifyCluster;
class IdentifyDelegate
{
public:
virtual ~IdentifyDelegate() = default;
/**
* @brief Called when identification starts.
* @param cluster The IdentifyCluster instance.
*/
virtual void OnIdentifyStart(IdentifyCluster & cluster) = 0;
/**
* @brief Called when identification stops.
* @param cluster The IdentifyCluster instance.
*/
virtual void OnIdentifyStop(IdentifyCluster & cluster) = 0;
/**
* @brief Called to trigger an effect.
* @param cluster The IdentifyCluster instance from which to get effect information.
*/
virtual void OnTriggerEffect(IdentifyCluster & cluster) = 0;
/**
* @brief Checks if the TriggerEffect command is enabled.
* @return True if the TriggerEffect command is enabled, false otherwise.
*/
virtual bool IsTriggerEffectEnabled() const = 0;
};
class IdentifyCluster : public DefaultServerCluster, public TimerContext
{
public:
/**
* @brief Configuration struct for IdentifyCluster.
*
* This struct is used to configure an IdentifyCluster instance. It requires mandatory parameters
* in its constructor and provides fluent-style `With...()` methods for setting optional parameters.
*
* Example:
* @code
* IdentifyCluster cluster(
* IdentifyCluster::Config(kEndpointId, myTimerDelegate)
* .WithDelegate(&myIdentifyDelegate)
* );
*
* Use `DefaultTimerDelegate` if you don't need a custom timer delegate implementation.
* @endcode
*/
struct Config
{
constexpr Config(EndpointId endpoint, TimerDelegate & delegate) : endpointId(endpoint), timerDelegate(delegate) {}
constexpr Config & WithIdentifyType(Identify::IdentifyTypeEnum type)
{
identifyType = type;
return *this;
}
constexpr Config & WithDelegate(IdentifyDelegate * delegate)
{
identifyDelegate = delegate;
return *this;
}
constexpr Config & WithEffectIdentifier(Identify::EffectIdentifierEnum effect)
{
effectIdentifier = effect;
return *this;
}
constexpr Config & WithEffectVariant(Identify::EffectVariantEnum variant)
{
effectVariant = variant;
return *this;
}
EndpointId endpointId;
Identify::IdentifyTypeEnum identifyType = Identify::IdentifyTypeEnum::kNone;
TimerDelegate & timerDelegate;
IdentifyDelegate * identifyDelegate = nullptr;
Identify::EffectIdentifierEnum effectIdentifier = Identify::EffectIdentifierEnum::kBlink;
Identify::EffectVariantEnum effectVariant = Identify::EffectVariantEnum::kDefault;
};
/**
* @brief Constructs a new IdentifyCluster object.
*
* @param config The configuration object for the cluster.
*/
IdentifyCluster(const Config & config);
/**
* @brief Implementation of ServerClusterInterface methods.
*/
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & encoder) override;
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,
AttributeValueDecoder & decoder) override;
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
std::optional<DataModel::ActionReturnStatus> InvokeCommand(const DataModel::InvokeRequest & request,
TLV::TLVReader & input_arguments, CommandHandler * handler) override;
CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path,
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) override;
/**
* @brief Called when the identify timer fires.
*/
void TimerFired() override;
/**
* @brief Stops the identification process.
*
* This method sets the IdentifyTime attribute to 0, which effectively stops the identification.
* It triggers the OnIdentifyStop callback if identification was in progress.
*/
void StopIdentifying();
Identify::EffectIdentifierEnum GetEffectIdentifier() const { return mEffectIdentifier; }
Identify::EffectVariantEnum GetEffectVariant() const { return mEffectVariant; }
Identify::IdentifyTypeEnum GetIdentifyType() const { return mIdentifyType; }
uint16_t GetIdentifyTime() const { return mIdentifyTime; }
private:
uint16_t mIdentifyTime;
Identify::IdentifyTypeEnum mIdentifyType;
IdentifyDelegate * mIdentifyDelegate;
Identify::EffectIdentifierEnum mEffectIdentifier;
Identify::EffectVariantEnum mEffectVariant;
TimerDelegate & mTimerDelegate;
enum class IdentifyTimeChangeSource
{
kClient,
kTimer,
};
/**
* @brief Helper method to handle changes to the IdentifyTime attribute.
*
* This method is called when the IdentifyTime attribute changes, either due to a client write,
* a command invocation, or a timer countdown. It manages the start/stop of identification
* callbacks and timer scheduling based on the new IdentifyTime value.
*
* @param source The source of the attribute change.
* @param newTime The new value of the IdentifyTime attribute.
*/
DataModel::ActionReturnStatus SetIdentifyTime(IdentifyTimeChangeSource source, uint16_t newTime);
};
} // namespace chip::app::Clusters