blob: 900aa0d04b71d999411d5f030388a7e01c3916a5 [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.
*/
#include <app/clusters/electrical-energy-measurement-server/CodegenIntegration.h>
#include <protocols/interaction_model/StatusCode.h>
#include <app/EventLogging.h>
#include <app/clusters/electrical-energy-measurement-server/ElectricalEnergyMeasurementDelegate.h>
#include <app/reporting/reporting.h>
#include <app/util/attribute-storage.h>
#include <app/util/config.h>
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
#include <data-model-providers/codegen/CodegenProcessingConfig.h>
#include <lib/support/CodeUtils.h>
#include <platform/DefaultTimerDelegate.h>
#include <lib/support/logging/CHIPLogging.h>
#include <zap-generated/gen_config.h>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Attributes;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs;
namespace {
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * EEMFirstInstance = nullptr;
inline void RegisterLegacyEEM(SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * inst)
{
inst->mpNext = EEMFirstInstance;
EEMFirstInstance = inst;
}
inline void UnregisterLegacyEEM(SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * inst)
{
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * current = EEMFirstInstance;
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * previous = nullptr;
while (current != nullptr)
{
if (current == inst)
{
if (previous == nullptr)
{
// Removing first element
EEMFirstInstance = current->mpNext;
}
else
{
previous->mpNext = current->mpNext;
}
break;
}
previous = current;
current = current->mpNext;
}
}
// Default empty accuracy used at construction time; real values are set later via SetMeasurementAccuracy.
const MeasurementAccuracyStruct::Type kDefaultAccuracy = {};
// No-op delegate for legacy CodegenIntegration path (readings are pushed via snapshot methods)
class NoOpEEMDelegate : public ElectricalEnergyMeasurement::Delegate
{
public:
DataModel::Nullable<int64_t> GetCumulativeEnergyImported() override { return DataModel::NullNullable; }
DataModel::Nullable<int64_t> GetCumulativeEnergyExported() override { return DataModel::NullNullable; }
DataModel::Nullable<int64_t> GetPeriodicEnergyImported() override { return DataModel::NullNullable; }
DataModel::Nullable<int64_t> GetPeriodicEnergyExported() override { return DataModel::NullNullable; }
};
NoOpEEMDelegate gNoOpDelegate;
DefaultTimerDelegate gDefaultTimerDelegate;
} // namespace
namespace chip {
namespace app {
namespace Clusters {
namespace ElectricalEnergyMeasurement {
ElectricalEnergyMeasurementAttrAccess::ElectricalEnergyMeasurementAttrAccess(BitMask<Feature> aFeature,
BitMask<OptionalAttributes> aOptionalAttrs,
EndpointId endpointId) :
ElectricalEnergyMeasurementAttrAccess(aFeature, aOptionalAttrs, endpointId, gNoOpDelegate, gDefaultTimerDelegate)
{}
ElectricalEnergyMeasurementAttrAccess::ElectricalEnergyMeasurementAttrAccess(BitMask<Feature> aFeature,
BitMask<OptionalAttributes> aOptionalAttrs,
EndpointId endpointId, Delegate & delegate,
TimerDelegate & timerDelegate) :
mCluster(ElectricalEnergyMeasurementCluster::Config{
.endpointId = endpointId,
.featureFlags = aFeature,
.optionalAttributes =
ElectricalEnergyMeasurementCluster::OptionalAttributesSet().Set<Attributes::CumulativeEnergyReset::Id>(
aOptionalAttrs.Has(OptionalAttributes::kOptionalAttributeCumulativeEnergyReset)),
.accuracyStruct = kDefaultAccuracy,
.delegate = delegate,
.timerDelegate = timerDelegate,
})
{
mClusterListNode.mValue = &mCluster.Cluster();
}
CHIP_ERROR SetMeasurementAccuracy(EndpointId endpointId, const MeasurementAccuracyStruct::Type & accuracy)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnError(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
return cluster->SetMeasurementAccuracy(accuracy);
}
CHIP_ERROR SetCumulativeReset(EndpointId endpointId,
const DataModel::Nullable<Structs::CumulativeEnergyResetStruct::Type> & cumulativeReset)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnError(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
return cluster->SetCumulativeEnergyReset(cumulativeReset);
}
bool NotifyCumulativeEnergyMeasured(EndpointId endpointId,
const DataModel::Nullable<EnergyMeasurementStruct::Type> & energyImported,
const DataModel::Nullable<EnergyMeasurementStruct::Type> & energyExported)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnValue(cluster != nullptr, false);
VerifyOrReturnValue(cluster->Features().Has(Feature::kCumulativeEnergy), false);
cluster->CumulativeEnergySnapshot(energyImported, energyExported);
return true;
}
bool NotifyPeriodicEnergyMeasured(EndpointId endpointId, const DataModel::Nullable<EnergyMeasurementStruct::Type> & energyImported,
const DataModel::Nullable<EnergyMeasurementStruct::Type> & energyExported)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnValue(cluster != nullptr, false);
VerifyOrReturnValue(cluster->Features().Has(Feature::kPeriodicEnergy), false);
cluster->PeriodicEnergySnapshot(energyImported, energyExported);
return true;
}
CHIP_ERROR ElectricalEnergyMeasurementAttrAccess::Init()
{
CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(mCluster.Registration());
RegisterLegacyEEM(&mClusterListNode);
if (err != CHIP_NO_ERROR)
{
#if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
ChipLogError(AppServer, "Failed to register cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
mCluster.Cluster().GetPaths()[0].mEndpointId, ChipLogValueMEI(ElectricalEnergyMeasurement::Id), err.Format());
#endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
}
return err;
}
void ElectricalEnergyMeasurementAttrAccess::Shutdown()
{
CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&mCluster.Cluster());
if (err != CHIP_NO_ERROR)
{
#if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
ChipLogError(AppServer, "Failed to unregister cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
mCluster.Cluster().GetPaths()[0].mEndpointId, ChipLogValueMEI(ElectricalEnergyMeasurement::Id), err.Format());
#endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
}
UnregisterLegacyEEM(&mClusterListNode);
}
bool ElectricalEnergyMeasurementAttrAccess::HasFeature(Feature aFeature) const
{
return mCluster.Cluster().Features().Has(aFeature);
}
bool ElectricalEnergyMeasurementAttrAccess::SupportsOptAttr(OptionalAttributes aOptionalAttrs) const
{
// Convert from OptionalAttributes enum to AttributeId and check OptionalAttributesSet from cluster
switch (aOptionalAttrs)
{
case OptionalAttributes::kOptionalAttributeCumulativeEnergyReset:
return mCluster.Cluster().OptionalAttributes().IsSet(CumulativeEnergyReset::Id);
default:
return false;
}
}
ElectricalEnergyMeasurementCluster * FindElectricalEnergyMeasurementClusterOnEndpoint(EndpointId endpointId)
{
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * current = EEMFirstInstance;
while (current != nullptr)
{
if (current->mValue != nullptr && current->mValue->GetPaths()[0].mEndpointId == endpointId)
{
return current->mValue;
}
current = current->mpNext;
}
return nullptr;
}
} // namespace ElectricalEnergyMeasurement
} // namespace Clusters
} // namespace app
} // namespace chip