blob: 79b55b3f4cadab40dfd1b260cdd92cccf368bc9e [file]
/*
* Copyright (c) 2026 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 "AmbientContextSensingDelegate.h"
#include "ambient-context-sensing-namespace.h"
#include <app-common/zap-generated/cluster-objects.h>
#include <app/server-cluster/DefaultServerCluster.h>
#include <app/server-cluster/OptionalAttributeSet.h>
#include <app/server-cluster/ServerClusterContext.h>
#include <lib/support/IntrusiveList.h>
#include <lib/support/Span.h>
#include <platform/DefaultTimerDelegate.h>
namespace chip::app::Clusters {
class AmbientContextSensingCluster : public DefaultServerCluster, public TimerContext
{
public:
struct Config
{
Config(TimerDelegate & timerDelegate) : mHoldTimeDelegate(timerDelegate) {}
Config & WithFeatures(BitMask<AmbientContextSensing::Feature> featureMap)
{
mFeatureMap = featureMap;
return *this;
}
Config & WithOptionalAttributes(uint32_t bits)
{
mOptionalAttributeBits = bits;
return *this;
}
Config & WithHoldTime(uint16_t aHoldTime,
const AmbientContextSensing::Structs::HoldTimeLimitsStruct::Type & aHoldTimeLimits)
{
mHoldTime = aHoldTime;
mHoldTimeLimits = aHoldTimeLimits;
return *this;
}
BitMask<AmbientContextSensing::Feature> mFeatureMap = 0;
uint32_t mOptionalAttributeBits = 0;
AmbientContextSensing::ObjectCountConfigType mObjectCountConfig = {
.countingObject = {
.namespaceID = kNamespaceIdentifiedObject,
.tag = static_cast<uint8_t>(TagIdentifiedObject::kUnknown),
},
.objectCountThreshold = AmbientContextSensing::kDefaultCountThreshold,
};
uint16_t mHoldTime = AmbientContextSensing::kDefaultHoldTimeDefault;
AmbientContextSensing::Structs::HoldTimeLimitsStruct::Type mHoldTimeLimits = {
.holdTimeMin = AmbientContextSensing::kDefaultHoldTimeMin,
.holdTimeMax = AmbientContextSensing::kDefaultHoldTimeMax,
.holdTimeDefault = AmbientContextSensing::kDefaultHoldTimeDefault
};
TimerDelegate & mHoldTimeDelegate;
};
using OptionalAttributeSet = chip::app::OptionalAttributeSet<AmbientContextSensing::Attributes::ObjectCount::Id>;
AmbientContextSensingCluster(EndpointId endpointId, const Config & config);
~AmbientContextSensingCluster() = default;
CHIP_ERROR Startup(ServerClusterContext & context) override;
void Shutdown(ClusterShutdownType shutdownType) override;
void SetDelegate(AmbientContextSensing::AmbientContextSensingDelegate * pDelegate) { mACSDelegate = pDelegate; }
// Server cluster implementation
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;
const BitMask<AmbientContextSensing::Feature> & GetFeatures() const { return mFeatureMap; }
bool GetHumanActivityDetected() { return mHumanActivityDetected; }
bool GetObjectIdentified() { return mObjectIdentified; }
bool GetAudioContextDetected() { return mAudioContextDetected; }
bool GetObjectCountThresholdReached() { return mObjectCountThresholdReached; }
CHIP_ERROR SetAmbientContextTypeSupported(const Span<AmbientContextSensing::SemanticTagType> & ACTypeList);
CHIP_ERROR AddDetection(const AmbientContextSensing::AmbientContextSensingType & sensedEvent);
DataModel::ActionReturnStatus SetObjectCountConfig(const AmbientContextSensing::ObjectCountConfigType & objectCountConfig);
AmbientContextSensing::ObjectCountConfigType GetObjectCountConfig() { return mObjectCountConfig; }
CHIP_ERROR SetObjectCount(uint16_t objectCount);
uint16_t GetObjectCount() { return mObjectCount; }
DataModel::ActionReturnStatus SetSimultaneousDetectionLimit(const uint8_t simultaneousDetectionLimit);
uint8_t GetSimultaneousDetectionLimit() { return mSimultaneousDetectionLimit; }
DataModel::ActionReturnStatus SetHoldTime(uint16_t holdTime);
uint16_t GetHoldTime() const { return mHoldTime; }
void SetHoldTimeLimits(const AmbientContextSensing::Structs::HoldTimeLimitsStruct::Type & holdTimeLimits);
AmbientContextSensing::Structs::HoldTimeLimitsStruct::Type GetHoldTimeLimits() { return mHoldTimeLimits; }
CHIP_ERROR SetPredictedActivity(const Span<AmbientContextSensing::PredictedActivityType> & predictedActivity);
void TimerFired() override;
private:
bool CompareAmbientContextSensed(const AmbientContextSensing::AmbientContextSensingType & sensedEvent,
const AmbientContextSensing::AmbientContextSensingType & newEvent);
CHIP_ERROR ReadAmbientContextTypeSupported(AttributeValueEncoder & encoder);
CHIP_ERROR ReadAmbientContextType(AttributeValueEncoder & encoder);
void SendDetectStartEvent(const AmbientContextSensing::AmbientContextSensed & ACSItem);
void SendDetectStartEvent(const bool objectCountReached, const uint16_t objectCount);
void SendDetectEndEvent(const uint64_t eventStartTimePos, const uint64_t eventStartTimeSys);
void UpdateDetectionAttributes();
void UpdateEventTimeout();
CHIP_ERROR CheckInputSupportedType(const Span<AmbientContextSensing::SemanticTagType> & ACTSupportedList);
bool IsSupportedEvent(const AmbientContextSensing::AmbientContextSensingType & sensedEvent);
void RemoveExpiredItems(IntrusiveList<AmbientContextSensing::AmbientContextSensed> & eventList, uint8_t & listSize,
const System::Clock::Timestamp & now);
System::Clock::Timestamp FindEarliestEndTimestamp();
CHIP_ERROR CheckPredictedActivity(const Span<AmbientContextSensing::PredictedActivityType> & predictedActivityList);
CHIP_ERROR ReadPredictedActivity(AttributeValueEncoder & encoder);
const BitMask<AmbientContextSensing::Feature> mFeatureMap;
const OptionalAttributeSet mOptionalAttributeSet;
bool mHumanActivityDetected = false;
bool mObjectIdentified = false;
bool mAudioContextDetected = false;
AmbientContextSensing::AmbientContextSensingDelegate * mACSDelegate = nullptr;
Span<AmbientContextSensing::SemanticTagType> mAmbientContextTypeSupportedList;
IntrusiveList<AmbientContextSensing::AmbientContextSensed> mAmbientContextTypeList;
uint8_t mAmbientContextTypeListSize = 0;
Span<AmbientContextSensing::PredictActivity> mPredictedActivityList;
uint8_t mSimultaneousDetectionLimit = AmbientContextSensing::kDefaultSimultaneousDetectionLimit;
bool mObjectCountThresholdReached = false;
AmbientContextSensing::ObjectCountConfigType mObjectCountConfig = {
.countingObject = {
.namespaceID = kNamespaceIdentifiedObject,
.tag = static_cast<uint8_t>(TagIdentifiedObject::kUnknown),
},
.objectCountThreshold = AmbientContextSensing::kDefaultCountThreshold,
};
uint16_t mObjectCount = 0;
System::Clock::Timestamp mObjectCountStartTime;
uint64_t mObjectCountStartEpoch;
System::Clock::Timestamp mObjectCountEndTime;
uint16_t mHoldTime = AmbientContextSensing::kDefaultHoldTimeDefault;
AmbientContextSensing::Structs::HoldTimeLimitsStruct::Type mHoldTimeLimits = {
.holdTimeMin = AmbientContextSensing::kDefaultHoldTimeMin,
.holdTimeMax = AmbientContextSensing::kDefaultHoldTimeMax,
.holdTimeDefault = AmbientContextSensing::kDefaultHoldTimeDefault
};
TimerDelegate & mHoldTimeDelegate;
};
} // namespace chip::app::Clusters