diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index b12b11b747b92e..ad7cb56245f2bd 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -3920,6 +3920,185 @@ provisional cluster ElectricalEnergyMeasurement = 145 { readonly attribute int16u clusterRevision = 65533; } +/** This cluster allows a client to manage the power draw of a device. An example of such a client could be an Energy Management System (EMS) which controls an Energy Smart Appliance (ESA). */ +provisional cluster DeviceEnergyManagement = 152 { + revision 2; + + enum CauseEnum : enum8 { + kNormalCompletion = 0; + kOffline = 1; + kFault = 2; + kUserOptOut = 3; + } + + enum CostTypeEnum : enum8 { + kFinancial = 0; + kGHGEmissions = 1; + kComfort = 2; + kTemperature = 3; + } + + enum ESAStateEnum : enum8 { + kOffline = 0; + kOnline = 1; + kFault = 2; + kUserOptOut = 3; + kPowerAdjustActive = 4; + kPaused = 5; + } + + enum ESATypeEnum : enum8 { + kEVSE = 0; + kSpaceHeating = 1; + kWaterHeating = 2; + kSpaceCooling = 3; + kSpaceHeatingCooling = 4; + kBatteryStorage = 5; + kSolarPV = 6; + kFridgeFreezer = 7; + kWashingMachine = 8; + kDishwasher = 9; + kCooking = 10; + kHomeWaterPump = 11; + kIrrigationWaterPump = 12; + kPoolPump = 13; + kOther = 255; + } + + bitmap Feature : bitmap32 { + kPowerAdjustment = 0x1; + kPowerForecastReporting = 0x2; + kStateForecastReporting = 0x4; + kForecastAdjustment = 0x8; + } + + struct CostStruct { + CostTypeEnum costType = 0; + int32s value = 1; + int8u decimalPoints = 2; + optional int16u currency = 3; + } + + struct SlotStruct { + elapsed_s minDuration = 0; + elapsed_s maxDuration = 1; + elapsed_s defaultDuration = 2; + elapsed_s elapsedSlotTime = 3; + elapsed_s remainingSlotTime = 4; + boolean slotIsPauseable = 5; + elapsed_s minPauseDuration = 6; + elapsed_s maxPauseDuration = 7; + optional int16u manufacturerESAState = 8; + optional power_mw nominalPower = 9; + optional power_mw minPower = 10; + optional power_mw maxPower = 11; + optional energy_mwh nominalEnergy = 12; + optional CostStruct costs[] = 13; + optional power_mw minPowerAdjustment = 14; + optional power_mw maxPowerAdjustment = 15; + optional elapsed_s minDurationAdjustment = 16; + optional elapsed_s maxDurationAdjustment = 17; + } + + struct ForecastStruct { + int16u forecastId = 0; + nullable int16u activeSlotNumber = 1; + epoch_s startTime = 2; + epoch_s endTime = 3; + optional nullable epoch_s earliestStartTime = 4; + optional epoch_s latestEndTime = 5; + boolean isPauseable = 6; + SlotStruct slots[] = 7; + } + + struct ConstraintsStruct { + epoch_s startTime = 0; + elapsed_s duration = 1; + optional power_mw nominalPower = 2; + optional energy_mwh maximumEnergy = 3; + optional int8s loadControl = 4; + } + + struct PowerAdjustStruct { + power_mw minPower = 0; + power_mw maxPower = 1; + elapsed_s minDuration = 2; + elapsed_s maxDuration = 3; + } + + struct SlotAdjustmentStruct { + int8u slotIndex = 0; + power_mw nominalPower = 1; + elapsed_s duration = 2; + } + + info event PowerAdjustStart = 0 { + } + + info event PowerAdjustEnd = 1 { + CauseEnum cause = 0; + elapsed_s duration = 1; + energy_mwh energyUse = 2; + } + + info event Paused = 2 { + } + + info event Resumed = 3 { + } + + readonly attribute ESATypeEnum ESAType = 0; + readonly attribute boolean ESACanGenerate = 1; + readonly attribute ESAStateEnum ESAState = 2; + readonly attribute power_mw absMinPower = 3; + readonly attribute power_mw absMaxPower = 4; + readonly attribute optional nullable PowerAdjustStruct powerAdjustmentCapability[] = 5; + readonly attribute optional nullable ForecastStruct forecast = 6; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct PowerAdjustRequestRequest { + power_mw power = 0; + elapsed_s duration = 1; + } + + request struct StartTimeAdjustRequestRequest { + epoch_s requestedStartTime = 0; + } + + request struct PauseRequestRequest { + elapsed_s duration = 0; + } + + request struct ModifyForecastRequestRequest { + int32u forecastId = 0; + SlotAdjustmentStruct slotAdjustments[] = 1; + } + + request struct RequestConstraintBasedForecastRequest { + ConstraintsStruct constraints[] = 0; + } + + /** Allows a client to request an adjustment in the power consumption of an ESA for a specified duration. */ + command PowerAdjustRequest(PowerAdjustRequestRequest): DefaultSuccess = 0; + /** Allows a client to cancel an ongoing PowerAdjustmentRequest operation. */ + command CancelPowerAdjustRequest(): DefaultSuccess = 1; + /** Allows a client to adjust the start time of a Forecast sequence that has not yet started operation (i.e. where the current Forecast StartTime is in the future). */ + command StartTimeAdjustRequest(StartTimeAdjustRequestRequest): DefaultSuccess = 2; + /** Allows a client to temporarily pause an operation and reduce the ESAs energy demand. */ + command PauseRequest(PauseRequestRequest): DefaultSuccess = 3; + /** Allows a client to cancel the PauseRequest command and enable earlier resumption of operation. */ + command ResumeRequest(): DefaultSuccess = 4; + /** Allows a client to modify a Forecast within the limits allowed by the ESA. */ + command ModifyForecastRequest(ModifyForecastRequestRequest): DefaultSuccess = 5; + /** Allows a client to ask the ESA to recompute its Forecast based on power and time constraints. */ + command RequestConstraintBasedForecast(RequestConstraintBasedForecastRequest): DefaultSuccess = 6; +} + /** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ provisional cluster EnergyEvse = 153 { revision 2; @@ -7737,25 +7916,53 @@ endpoint 1 { ram attribute clusterRevision default = 1; } + server cluster DeviceEnergyManagement { + emits event PowerAdjustStart; + emits event PowerAdjustEnd; + emits event Paused; + emits event Resumed; + callback attribute ESAType; + callback attribute ESACanGenerate; + callback attribute ESAState; + callback attribute absMinPower; + callback attribute absMaxPower; + callback attribute powerAdjustmentCapability; + callback attribute forecast; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 2; + + handle command PowerAdjustRequest; + handle command CancelPowerAdjustRequest; + handle command StartTimeAdjustRequest; + handle command PauseRequest; + handle command ResumeRequest; + handle command ModifyForecastRequest; + handle command RequestConstraintBasedForecast; + } + server cluster EnergyEvse { - callback attribute state default = 0; - callback attribute supplyState default = 0; - callback attribute faultState default = 0; - callback attribute chargingEnabledUntil default = 0; - callback attribute dischargingEnabledUntil default = 0; - callback attribute circuitCapacity default = 0; - callback attribute minimumChargeCurrent default = 6000; - callback attribute maximumChargeCurrent default = 0; - callback attribute maximumDischargeCurrent default = 0; - callback attribute userMaximumChargeCurrent default = 0; - callback attribute randomizationDelayWindow default = 600; + callback attribute state; + callback attribute supplyState; + callback attribute faultState; + callback attribute chargingEnabledUntil; + callback attribute dischargingEnabledUntil; + callback attribute circuitCapacity; + callback attribute minimumChargeCurrent; + callback attribute maximumChargeCurrent; + callback attribute maximumDischargeCurrent; + callback attribute userMaximumChargeCurrent; + callback attribute randomizationDelayWindow; callback attribute numberOfWeeklyTargets default = 0; callback attribute numberOfDailyTargets default = 1; callback attribute nextChargeStartTime; callback attribute nextChargeTargetTime; callback attribute nextChargeRequiredEnergy; callback attribute nextChargeTargetSoC; - callback attribute approximateEVEfficiency default = 0xFFFF; + callback attribute approximateEVEfficiency; callback attribute stateOfCharge; callback attribute batteryCapacity; callback attribute vehicleID; @@ -7767,7 +7974,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; + callback attribute featureMap; ram attribute clusterRevision default = 2; handle command GetTargetsResponse; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index a24d3db39a2b65..9013ea3140e6db 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -12640,6 +12640,313 @@ } ] }, + { + "name": "Device Energy Management", + "code": 152, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "PowerAdjustRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CancelPowerAdjustRequest", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartTimeAdjustRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseRequest", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ResumeRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ModifyForecastRequest", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RequestConstraintBasedForecast", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "ESAType", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "ESATypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESACanGenerate", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESAState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "ESAStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinPower", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxPower", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PowerAdjustmentCapability", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Forecast", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "ForecastStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "PowerAdjustStart", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "PowerAdjustEnd", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Paused", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Resumed", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, { "name": "Energy EVSE", "code": 153, @@ -13186,7 +13493,7 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0", diff --git a/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp new file mode 100644 index 00000000000000..385c1cfa43c8ee --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2023 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 + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; + +static std::unique_ptr gDelegate; +static std::unique_ptr gInstance; + +void emberAfDeviceEnergyManagementClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gInstance == nullptr); + + CHIP_ERROR err; + + if (gDelegate || gInstance) + { + ChipLogError(AppServer, "DEM Instance or Delegate already exist."); + return; + } + + gDelegate = std::make_unique(); + if (!gDelegate) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementDelegate"); + return; + } + + /* Manufacturer may optionally not support all features, commands & attributes */ + gInstance = std::make_unique( + endpointId, *gDelegate, + BitMask( + DeviceEnergyManagement::Feature::kPowerForecastReporting, DeviceEnergyManagement::Feature::kStateForecastReporting, + DeviceEnergyManagement::Feature::kPowerAdjustment, DeviceEnergyManagement::Feature::kForecastAdjustment), + BitMask(OptionalCommands::kSupportsModifyForecastRequest, + OptionalCommands::kSupportsRequestConstraintBasedForecast)); + + if (!gInstance) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementManager"); + gDelegate.reset(); + return; + } + + err = gInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gInstance"); + gInstance.reset(); + gDelegate.reset(); + return; + } +} diff --git a/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp index a0773de104c187..f9983d47883852 100644 --- a/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp @@ -22,25 +22,26 @@ using namespace chip; using namespace chip::app::Clusters; using namespace chip::app::Clusters::EnergyEvse; -static EnergyEvseDelegate * gDelegate = nullptr; -static EnergyEvseManager * gInstance = nullptr; +static std::unique_ptr gDelegate; +static std::unique_ptr gInstance; void emberAfEnergyEvseClusterInitCallback(chip::EndpointId endpointId) { VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. - VerifyOrDie(gInstance == nullptr); - gDelegate = new EnergyEvseDelegate(); - if (gDelegate != nullptr) + VerifyOrDie(!gInstance); + + gDelegate = std::make_unique(); + if (gDelegate) { - gInstance = - new EnergyEvseManager(endpointId, *gDelegate, - BitMask( - EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge, - EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting, EnergyEvse::Feature::kV2x), - BitMask(OptionalAttributes::kSupportsUserMaximumChargingCurrent, - OptionalAttributes::kSupportsRandomizationWindow, - OptionalAttributes::kSupportsApproximateEvEfficiency), - BitMask(OptionalCommands::kSupportsStartDiagnostics)); + gInstance = std::make_unique( + endpointId, *gDelegate, + BitMask(EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge, + EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting, + EnergyEvse::Feature::kV2x), + BitMask(OptionalAttributes::kSupportsUserMaximumChargingCurrent, + OptionalAttributes::kSupportsRandomizationWindow, + OptionalAttributes::kSupportsApproximateEvEfficiency), + BitMask(OptionalCommands::kSupportsStartDiagnostics)); gInstance->Init(); /* Register Attribute & Command handlers */ } diff --git a/examples/all-clusters-app/ameba/chip_main.cmake b/examples/all-clusters-app/ameba/chip_main.cmake index e68398afdf625d..66528a9941141a 100755 --- a/examples/all-clusters-app/ameba/chip_main.cmake +++ b/examples/all-clusters-app/ameba/chip_main.cmake @@ -156,6 +156,7 @@ list( ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/air-quality-instance.cpp ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp + ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp ${chip_dir}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp @@ -175,6 +176,8 @@ list( ${chip_dir}/examples/all-clusters-app/ameba/main/ManualOperationCommand.cpp ${chip_dir}/examples/all-clusters-app/ameba/main/SmokeCOAlarmManager.cpp + ${chip_dir}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp + ${chip_dir}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp diff --git a/examples/all-clusters-app/asr/BUILD.gn b/examples/all-clusters-app/asr/BUILD.gn index 1c23617af66262..263bd8cf7734b7 100755 --- a/examples/all-clusters-app/asr/BUILD.gn +++ b/examples/all-clusters-app/asr/BUILD.gn @@ -74,6 +74,7 @@ asr_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/air-quality-instance.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -81,6 +82,8 @@ asr_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "${examples_plat_dir}/ButtonHandler.cpp", diff --git a/examples/all-clusters-app/cc13x2x7_26x2x7/BUILD.gn b/examples/all-clusters-app/cc13x2x7_26x2x7/BUILD.gn index 26c0f67e389a0c..6ec6202ea21209 100644 --- a/examples/all-clusters-app/cc13x2x7_26x2x7/BUILD.gn +++ b/examples/all-clusters-app/cc13x2x7_26x2x7/BUILD.gn @@ -79,6 +79,7 @@ ti_simplelink_executable("all-clusters-app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -86,6 +87,8 @@ ti_simplelink_executable("all-clusters-app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "${chip_root}/examples/providers/DeviceInfoProviderImpl.cpp", diff --git a/examples/all-clusters-app/cc13x4_26x4/BUILD.gn b/examples/all-clusters-app/cc13x4_26x4/BUILD.gn index e9492d7a223f42..02dbebf7e6d8c9 100644 --- a/examples/all-clusters-app/cc13x4_26x4/BUILD.gn +++ b/examples/all-clusters-app/cc13x4_26x4/BUILD.gn @@ -82,6 +82,7 @@ ti_simplelink_executable("all-clusters-app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -89,6 +90,8 @@ ti_simplelink_executable("all-clusters-app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "${chip_root}/examples/providers/DeviceInfoProviderImpl.cpp", diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 89ce7c1c872160..623e2ded547abe 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -75,6 +75,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/diagnostic-logs-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/device-energy-management-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ethernet-network-diagnostics-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/localization-configuration-server" diff --git a/examples/all-clusters-app/infineon/psoc6/BUILD.gn b/examples/all-clusters-app/infineon/psoc6/BUILD.gn index f4469b9c7bc290..f2b9ab939d6f38 100644 --- a/examples/all-clusters-app/infineon/psoc6/BUILD.gn +++ b/examples/all-clusters-app/infineon/psoc6/BUILD.gn @@ -110,6 +110,7 @@ psoc6_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/air-quality-instance.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -117,6 +118,8 @@ psoc6_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "${examples_plat_dir}/LEDWidget.cpp", diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index b2cc122b5090ab..8b031d769773e4 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -26,6 +26,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/boolcfg-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/dishwasher-alarm-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/dishwasher-mode.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", @@ -42,6 +43,8 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/tcc-mode.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "AllClustersCommandDelegate.cpp", diff --git a/examples/all-clusters-app/mbed/CMakeLists.txt b/examples/all-clusters-app/mbed/CMakeLists.txt index 28104e85f0c3b1..f2b6d9f5e88d27 100644 --- a/examples/all-clusters-app/mbed/CMakeLists.txt +++ b/examples/all-clusters-app/mbed/CMakeLists.txt @@ -65,6 +65,7 @@ target_sources(${APP_TARGET} PRIVATE ${ALL_CLUSTERS_COMMON}/src/air-quality-instance.cpp ${ALL_CLUSTERS_COMMON}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON}/src/fan-stub.cpp + ${ALL_CLUSTERS_COMMON}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON}/src/energy-evse-stub.cpp ${ALL_CLUSTERS_COMMON}/src/oven-modes.cpp ${ALL_CLUSTERS_COMMON}/src/resource-monitoring-delegates.cpp @@ -73,6 +74,9 @@ target_sources(${APP_TARGET} PRIVATE ${ALL_CLUSTERS_COMMON}/src/static-supported-temperature-levels.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseManager.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp + ) chip_configure_data_model(${APP_TARGET} diff --git a/examples/all-clusters-app/nrfconnect/CMakeLists.txt b/examples/all-clusters-app/nrfconnect/CMakeLists.txt index 48499c29712d40..49bf4fb7f95e3a 100644 --- a/examples/all-clusters-app/nrfconnect/CMakeLists.txt +++ b/examples/all-clusters-app/nrfconnect/CMakeLists.txt @@ -65,10 +65,13 @@ target_sources(app PRIVATE ${ALL_CLUSTERS_COMMON_DIR}/src/fan-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/oven-modes.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/energy-evse-stub.cpp + ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/binding-handler.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/air-quality-instance.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/resource-monitoring-delegates.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseManager.cpp ${NRFCONNECT_COMMON}/util/LEDWidget.cpp) diff --git a/examples/all-clusters-app/nxp/mw320/BUILD.gn b/examples/all-clusters-app/nxp/mw320/BUILD.gn index 01bba26479a7af..a858c18e87fed2 100644 --- a/examples/all-clusters-app/nxp/mw320/BUILD.gn +++ b/examples/all-clusters-app/nxp/mw320/BUILD.gn @@ -78,6 +78,7 @@ mw320_executable("shell_mw320") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/air-quality-instance.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -85,6 +86,8 @@ mw320_executable("shell_mw320") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", "${chip_root}/src/lib/shell/streamer_mw320.cpp", diff --git a/examples/all-clusters-app/openiotsdk/CMakeLists.txt b/examples/all-clusters-app/openiotsdk/CMakeLists.txt index 60b5bdddf40740..3b50f286b1683b 100644 --- a/examples/all-clusters-app/openiotsdk/CMakeLists.txt +++ b/examples/all-clusters-app/openiotsdk/CMakeLists.txt @@ -60,12 +60,15 @@ target_sources(${APP_TARGET} ${ALL_CLUSTERS_COMMON}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON}/src/fan-stub.cpp ${ALL_CLUSTERS_COMMON}/src/oven-modes.cpp + ${ALL_CLUSTERS_COMMON}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON}/src/energy-evse-stub.cpp ${ALL_CLUSTERS_COMMON}/src/resource-monitoring-delegates.cpp ${ALL_CLUSTERS_COMMON}/src/static-supported-modes-manager.cpp ${ALL_CLUSTERS_COMMON}/src/binding-handler.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseManager.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp ) target_link_libraries(${APP_TARGET} diff --git a/examples/all-clusters-app/telink/CMakeLists.txt b/examples/all-clusters-app/telink/CMakeLists.txt index 3571869e8949aa..ae715a8c41ebfb 100644 --- a/examples/all-clusters-app/telink/CMakeLists.txt +++ b/examples/all-clusters-app/telink/CMakeLists.txt @@ -82,10 +82,13 @@ target_sources(app PRIVATE ${ALL_CLUSTERS_COMMON_DIR}/src/air-quality-instance.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/fan-stub.cpp + ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/energy-evse-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/resource-monitoring-delegates.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseManager.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp ${TELINK_COMMON}/common/src/mainCommon.cpp ${TELINK_COMMON}/common/src/AppTaskCommon.cpp ${TELINK_COMMON}/util/src/LEDWidget.cpp diff --git a/examples/all-clusters-app/tizen/BUILD.gn b/examples/all-clusters-app/tizen/BUILD.gn index 202d288f87053c..e9bb7f56e4bfaa 100644 --- a/examples/all-clusters-app/tizen/BUILD.gn +++ b/examples/all-clusters-app/tizen/BUILD.gn @@ -27,6 +27,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/concentration-measurement-instances.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", @@ -34,6 +35,8 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", ] diff --git a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt index cb38515a1a8770..cae8b64315a232 100644 --- a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt @@ -81,6 +81,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/diagnostic-logs-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/door-lock-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/device-energy-management-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ethernet-network-diagnostics-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/localization-configuration-server" diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index d48a22c42cc51e..753c428234a038 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -900,6 +900,185 @@ cluster GroupKeyManagement = 63 { fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; } +/** This cluster allows a client to manage the power draw of a device. An example of such a client could be an Energy Management System (EMS) which controls an Energy Smart Appliance (ESA). */ +provisional cluster DeviceEnergyManagement = 152 { + revision 2; + + enum CauseEnum : enum8 { + kNormalCompletion = 0; + kOffline = 1; + kFault = 2; + kUserOptOut = 3; + } + + enum CostTypeEnum : enum8 { + kFinancial = 0; + kGHGEmissions = 1; + kComfort = 2; + kTemperature = 3; + } + + enum ESAStateEnum : enum8 { + kOffline = 0; + kOnline = 1; + kFault = 2; + kUserOptOut = 3; + kPowerAdjustActive = 4; + kPaused = 5; + } + + enum ESATypeEnum : enum8 { + kEVSE = 0; + kSpaceHeating = 1; + kWaterHeating = 2; + kSpaceCooling = 3; + kSpaceHeatingCooling = 4; + kBatteryStorage = 5; + kSolarPV = 6; + kFridgeFreezer = 7; + kWashingMachine = 8; + kDishwasher = 9; + kCooking = 10; + kHomeWaterPump = 11; + kIrrigationWaterPump = 12; + kPoolPump = 13; + kOther = 255; + } + + bitmap Feature : bitmap32 { + kPowerAdjustment = 0x1; + kPowerForecastReporting = 0x2; + kStateForecastReporting = 0x4; + kForecastAdjustment = 0x8; + } + + struct CostStruct { + CostTypeEnum costType = 0; + int32s value = 1; + int8u decimalPoints = 2; + optional int16u currency = 3; + } + + struct SlotStruct { + elapsed_s minDuration = 0; + elapsed_s maxDuration = 1; + elapsed_s defaultDuration = 2; + elapsed_s elapsedSlotTime = 3; + elapsed_s remainingSlotTime = 4; + boolean slotIsPauseable = 5; + elapsed_s minPauseDuration = 6; + elapsed_s maxPauseDuration = 7; + optional int16u manufacturerESAState = 8; + optional power_mw nominalPower = 9; + optional power_mw minPower = 10; + optional power_mw maxPower = 11; + optional energy_mwh nominalEnergy = 12; + optional CostStruct costs[] = 13; + optional power_mw minPowerAdjustment = 14; + optional power_mw maxPowerAdjustment = 15; + optional elapsed_s minDurationAdjustment = 16; + optional elapsed_s maxDurationAdjustment = 17; + } + + struct ForecastStruct { + int16u forecastId = 0; + nullable int16u activeSlotNumber = 1; + epoch_s startTime = 2; + epoch_s endTime = 3; + optional nullable epoch_s earliestStartTime = 4; + optional epoch_s latestEndTime = 5; + boolean isPauseable = 6; + SlotStruct slots[] = 7; + } + + struct ConstraintsStruct { + epoch_s startTime = 0; + elapsed_s duration = 1; + optional power_mw nominalPower = 2; + optional energy_mwh maximumEnergy = 3; + optional int8s loadControl = 4; + } + + struct PowerAdjustStruct { + power_mw minPower = 0; + power_mw maxPower = 1; + elapsed_s minDuration = 2; + elapsed_s maxDuration = 3; + } + + struct SlotAdjustmentStruct { + int8u slotIndex = 0; + power_mw nominalPower = 1; + elapsed_s duration = 2; + } + + info event PowerAdjustStart = 0 { + } + + info event PowerAdjustEnd = 1 { + CauseEnum cause = 0; + elapsed_s duration = 1; + energy_mwh energyUse = 2; + } + + info event Paused = 2 { + } + + info event Resumed = 3 { + } + + readonly attribute ESATypeEnum ESAType = 0; + readonly attribute boolean ESACanGenerate = 1; + readonly attribute ESAStateEnum ESAState = 2; + readonly attribute power_mw absMinPower = 3; + readonly attribute power_mw absMaxPower = 4; + readonly attribute optional nullable PowerAdjustStruct powerAdjustmentCapability[] = 5; + readonly attribute optional nullable ForecastStruct forecast = 6; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct PowerAdjustRequestRequest { + power_mw power = 0; + elapsed_s duration = 1; + } + + request struct StartTimeAdjustRequestRequest { + epoch_s requestedStartTime = 0; + } + + request struct PauseRequestRequest { + elapsed_s duration = 0; + } + + request struct ModifyForecastRequestRequest { + int32u forecastId = 0; + SlotAdjustmentStruct slotAdjustments[] = 1; + } + + request struct RequestConstraintBasedForecastRequest { + ConstraintsStruct constraints[] = 0; + } + + /** Allows a client to request an adjustment in the power consumption of an ESA for a specified duration. */ + command PowerAdjustRequest(PowerAdjustRequestRequest): DefaultSuccess = 0; + /** Allows a client to cancel an ongoing PowerAdjustmentRequest operation. */ + command CancelPowerAdjustRequest(): DefaultSuccess = 1; + /** Allows a client to adjust the start time of a Forecast sequence that has not yet started operation (i.e. where the current Forecast StartTime is in the future). */ + command StartTimeAdjustRequest(StartTimeAdjustRequestRequest): DefaultSuccess = 2; + /** Allows a client to temporarily pause an operation and reduce the ESAs energy demand. */ + command PauseRequest(PauseRequestRequest): DefaultSuccess = 3; + /** Allows a client to cancel the PauseRequest command and enable earlier resumption of operation. */ + command ResumeRequest(): DefaultSuccess = 4; + /** Allows a client to modify a Forecast within the limits allowed by the ESA. */ + command ModifyForecastRequest(ModifyForecastRequestRequest): DefaultSuccess = 5; + /** Allows a client to ask the ESA to recompute its Forecast based on power and time constraints. */ + command RequestConstraintBasedForecast(RequestConstraintBasedForecastRequest): DefaultSuccess = 6; +} + /** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ provisional cluster EnergyEvse = 153 { revision 2; @@ -1290,6 +1469,34 @@ endpoint 1 { callback attribute clusterRevision; } + server cluster DeviceEnergyManagement { + emits event PowerAdjustStart; + emits event PowerAdjustEnd; + emits event Paused; + emits event Resumed; + callback attribute ESAType; + callback attribute ESACanGenerate; + callback attribute ESAState; + callback attribute absMinPower; + callback attribute absMaxPower; + callback attribute powerAdjustmentCapability; + callback attribute forecast; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 2; + + handle command PowerAdjustRequest; + handle command CancelPowerAdjustRequest; + handle command StartTimeAdjustRequest; + handle command PauseRequest; + handle command ResumeRequest; + handle command ModifyForecastRequest; + handle command RequestConstraintBasedForecast; + } + server cluster EnergyEvse { emits event EVConnected; emits event EVNotDetected; @@ -1300,33 +1507,33 @@ endpoint 1 { callback attribute state; callback attribute supplyState; callback attribute faultState; - callback attribute chargingEnabledUntil default = 0; - callback attribute dischargingEnabledUntil default = 0; - callback attribute circuitCapacity default = 0; - callback attribute minimumChargeCurrent default = 6000; - callback attribute maximumChargeCurrent default = 0; - callback attribute maximumDischargeCurrent default = 0; - callback attribute userMaximumChargeCurrent default = 0; - callback attribute randomizationDelayWindow default = 600; + callback attribute chargingEnabledUntil; + callback attribute dischargingEnabledUntil; + callback attribute circuitCapacity; + callback attribute minimumChargeCurrent; + callback attribute maximumChargeCurrent; + callback attribute maximumDischargeCurrent; + callback attribute userMaximumChargeCurrent; + callback attribute randomizationDelayWindow; callback attribute numberOfWeeklyTargets default = 0; callback attribute numberOfDailyTargets default = 1; callback attribute nextChargeStartTime; callback attribute nextChargeTargetTime; callback attribute nextChargeRequiredEnergy; callback attribute nextChargeTargetSoC; - callback attribute approximateEVEfficiency default = 0xFFFF; + callback attribute approximateEVEfficiency; callback attribute stateOfCharge; callback attribute batteryCapacity; callback attribute vehicleID; - callback attribute sessionID default = 0; - callback attribute sessionDuration default = 0; - callback attribute sessionEnergyCharged default = 0; - callback attribute sessionEnergyDischarged default = 0; + callback attribute sessionID; + callback attribute sessionDuration; + callback attribute sessionEnergyCharged; + callback attribute sessionEnergyDischarged; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 1; + callback attribute featureMap; ram attribute clusterRevision default = 2; handle command GetTargetsResponse; diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.zap b/examples/energy-management-app/energy-management-common/energy-management-app.zap index 55d62101227dab..8ed4aa6e2167d7 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.zap +++ b/examples/energy-management-app/energy-management-common/energy-management-app.zap @@ -2517,6 +2517,313 @@ } ] }, + { + "name": "Device Energy Management", + "code": 152, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "PowerAdjustRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CancelPowerAdjustRequest", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartTimeAdjustRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseRequest", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ResumeRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ModifyForecastRequest", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RequestConstraintBasedForecast", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "ESAType", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "ESATypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESACanGenerate", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESAState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "ESAStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinPower", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxPower", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PowerAdjustmentCapability", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Forecast", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "ForecastStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "PowerAdjustStart", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "PowerAdjustEnd", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Paused", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Resumed", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, { "name": "Energy EVSE", "code": 153, @@ -3063,7 +3370,7 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "1", diff --git a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h new file mode 100644 index 00000000000000..464a683510b3d7 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2023 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/clusters/device-energy-management-server/device-energy-management-server.h" + +#include +#include +#include + +using chip::Protocols::InteractionModel::Status; +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +/** + * The application delegate. + */ +class DeviceEnergyManagementDelegate : public DeviceEnergyManagement::Delegate +{ +public: + virtual Status PowerAdjustRequest(const int64_t power, const uint32_t duration) override; + virtual Status CancelPowerAdjustRequest() override; + virtual Status StartTimeAdjustRequest(const uint32_t requestedStartTime) override; + virtual Status PauseRequest(const uint32_t duration) override; + virtual Status ResumeRequest() override; + virtual Status + ModifyForecastRequest(const uint32_t forecastId, + const DataModel::DecodableList & slotAdjustments) override; + virtual Status RequestConstraintBasedForecast( + const DataModel::DecodableList & constraints) override; + + // ------------------------------------------------------------------ + // Get attribute methods + virtual ESATypeEnum GetESAType() override; + virtual bool GetESACanGenerate() override; + virtual ESAStateEnum GetESAState() override; + virtual int64_t GetAbsMinPower() override; + virtual int64_t GetAbsMaxPower() override; + virtual Attributes::PowerAdjustmentCapability::TypeInfo::Type GetPowerAdjustmentCapability() override; + virtual DataModel::Nullable GetForecast() override; + + // ------------------------------------------------------------------ + // Set attribute methods + virtual CHIP_ERROR SetESAType(ESATypeEnum) override; + virtual CHIP_ERROR SetESACanGenerate(bool) override; + virtual CHIP_ERROR SetESAState(ESAStateEnum) override; + virtual CHIP_ERROR SetAbsMinPower(int64_t) override; + virtual CHIP_ERROR SetAbsMaxPower(int64_t) override; + virtual CHIP_ERROR SetPowerAdjustmentCapability(Attributes::PowerAdjustmentCapability::TypeInfo::Type) override; + virtual CHIP_ERROR SetForecast(DataModel::Nullable) override; + +private: + ESATypeEnum mEsaType; + bool mEsaCanGenerate; + ESAStateEnum mEsaState; + int64_t mAbsMinPower; + int64_t mAbsMaxPower; + Attributes::PowerAdjustmentCapability::TypeInfo::Type mPowerAdjustmentCapability; + DataModel::Nullable mForecast; +}; + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h new file mode 100644 index 00000000000000..6d131dd4ae90fa --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2023 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 +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { + +using namespace chip::app::Clusters::DeviceEnergyManagement; +class DeviceEnergyManagementManager : public Instance +{ +public: + DeviceEnergyManagementManager(EndpointId aEndpointId, DeviceEnergyManagementDelegate & aDelegate, Feature aFeature, + OptionalCommands aOptionalCmds) : + DeviceEnergyManagement::Instance(aEndpointId, aDelegate, aFeature, aOptionalCmds) + { + mDelegate = &aDelegate; + } + + // Delete copy constructor and assignment operator. + DeviceEnergyManagementManager(const DeviceEnergyManagementManager &) = delete; + DeviceEnergyManagementManager(const DeviceEnergyManagementManager &&) = delete; + DeviceEnergyManagementManager & operator=(const DeviceEnergyManagementManager &) = delete; + + CHIP_ERROR Init(); + void Shutdown(); + + DeviceEnergyManagementDelegate * GetDelegate() { return mDelegate; }; + +private: + DeviceEnergyManagementDelegate * mDelegate; +}; + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h index 5bf253aef81d9b..df757f7374e672 100644 --- a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h +++ b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h @@ -18,6 +18,7 @@ #pragma once +#include #include using chip::Protocols::InteractionModel::Status; diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h index a6a64f35ee9767..fc0d41b9259643 100644 --- a/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h +++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h @@ -26,8 +26,8 @@ namespace chip { namespace app { namespace Clusters { +namespace EnergyEvse { -using namespace chip::app::Clusters::EnergyEvse; class EnergyEvseManager : public Instance { public: @@ -54,6 +54,7 @@ class EnergyEvseManager : public Instance EnergyEvseDelegate * mDelegate; }; +} // namespace EnergyEvse } // namespace Clusters } // namespace app } // namespace chip diff --git a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp new file mode 100644 index 00000000000000..4d4d9bf05bbdbb --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp @@ -0,0 +1,344 @@ +/* + * + * Copyright (c) 2023 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 "DeviceEnergyManagementDelegateImpl.h" + +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; +using namespace chip::app::Clusters::DeviceEnergyManagement::Attributes; + +using chip::Optional; +using namespace chip::app; +using CostsList = DataModel::List; + +/** + * @brief Delegate handler for PowerAdjustRequest + * + * Note: checking of the validity of the PowerAdjustRequest has been done by the lower layer + * + * This function needs to notify the appliance that it should apply a new power setting. + * It should: + * 1) notify the appliance - if the appliance hardware cannot be adjusted, then return Failure + * 2) start a timer (or restart the existing PowerAdjust timer) for duration seconds + * 3) generate a PowerAdjustStart event (if there is not an existing PowerAdjustRequest running) + * 4) if appropriate, update the forecast with the new expected end time + * + * and when the timer expires: + * 5) notify the appliance's that it can resume its intended power setting (or go idle) + * 6) generate a PowerAdjustEnd event with cause NormalCompletion + * 7) if necessary, update the forecast with new expected end time + */ +Status DeviceEnergyManagementDelegate::PowerAdjustRequest(const int64_t power, const uint32_t duration) +{ + Status status = Status::UnsupportedCommand; // Status::Success; + + // TODO: implement + mEsaState = ESAStateEnum::kPowerAdjustActive; + + // TODO: Generate a PowerAdjustStart Event, then begins to adjust its power + // When done, raise PowerAdjustEnd & ESAState set to kOnline. + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAState::Id); + + return status; +} +/** + * @brief Delegate handler for CancelPowerAdjustRequest + * + * Note: checking of the validity of the CancelPowerAdjustRequest has been done by the lower layer + * + * This function needs to notify the appliance that it should resume its intended power setting (or go idle). + + * It should: + * 1) notify the appliance's that it can resume its intended power setting (or go idle) + * 2) generate a PowerAdjustEnd event with cause code Cancelled + * 3) if necessary, update the forecast with new expected end time + */ +Status DeviceEnergyManagementDelegate::CancelPowerAdjustRequest() +{ + Status status = Status::UnsupportedCommand; // Status::Success; + + // TODO: implement + /* TODO: If the command is accepted, the ESA SHALL generate an PowerAdjustEnd Event. */ + mEsaState = ESAStateEnum::kOnline; + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAState::Id); + + return status; +} + +/** + * @brief Delegate handler for StartTimeAdjustRequest + * + * Note: checking of the validity of the StartTimeAdjustRequest has been done by the lower layer + * + * This function needs to notify the appliance that the forecast has been updated by a client. + * + * It should: + * 1) update the forecast attribute with the revised start time + * 2) send a callback notification to the appliance so it can refresh its internal schedule + */ +Status DeviceEnergyManagementDelegate::StartTimeAdjustRequest(const uint32_t requestedStartTime) +{ + DataModel::Nullable forecast = GetForecast(); + + if (forecast.IsNull()) + { + return Status::Failure; + } + + uint32_t duration = forecast.Value().endTime - forecast.Value().startTime; // the current entire forecast duration + + /* Modify start time and end time */ + forecast.Value().startTime = requestedStartTime; + forecast.Value().endTime = requestedStartTime + duration; + + SetForecast(forecast); // This will increment forecast ID + + // TODO: callback to the appliance to notify it of a new start time + + return Status::Success; +} +/** + * @brief Delegate handler for Pause Request + * + * Note: checking of the validity of the Pause Request has been done by the lower layer + * + * This function needs to notify the appliance that it should now pause. + * It should: + * 1) pause the appliance - if the appliance hardware cannot be paused, then return Failure + * 2) start a timer for duration seconds + * 3) generate a Paused event + * 4) update the forecast with the new expected end time + * + * and when the timer expires: + * 5) restore the appliance's operational state + * 6) generate a Resumed event + * 7) if necessary, update the forecast with new expected end time + */ +Status DeviceEnergyManagementDelegate::PauseRequest(const uint32_t duration) +{ + Status status = Status::UnsupportedCommand; // Status::Success; + // TODO: implement the behaviour above + return status; +} + +/** + * @brief Delegate handler for ResumeRequest + * + * Note: checking of the validity of the ResumeRequest has been done by the lower layer + * + * This function needs to notify the appliance that it should now resume operation + * + * It should: + * 1) restore the appliance's operational state + * 2) generate a Resumed event + * 3) update the forecast with new expected end time (given that the pause duration was shorter than originally requested) + * + */ +Status DeviceEnergyManagementDelegate::ResumeRequest() +{ + Status status = Status::UnsupportedCommand; // Status::Success; + + // TODO: implement the behaviour above + SetESAState(ESAStateEnum::kOnline); + + return status; +} + +/** + * @brief Delegate handler for ModifyForecastRequest + * + * Note: Only basic checking of the validity of the ModifyForecastRequest has been + * done by the lower layer. This is a more complex use-case and requires higher-level + * work by the delegate. + * + * It should: + * 1) determine if the new forecast adjustments are acceptable to the appliance + * - if not return Failure. For example, if it may cause the home to be too hot + * or too cold, or a battery to be insufficiently charged + * 2) if the slot adjustments are acceptable, then update the forecast + * 3) notify the appliance to follow the revised schedule + */ +Status DeviceEnergyManagementDelegate::ModifyForecastRequest( + const uint32_t forecastId, const DataModel::DecodableList & slotAdjustments) +{ + Status status = Status::UnsupportedCommand; // Status::Success; + + // TODO: implement the behaviour above + return status; +} + +/** + * @brief Delegate handler for RequestConstraintBasedForecast + * + * Note: Only basic checking of the validity of the RequestConstraintBasedForecast has been + * done by the lower layer. This is a more complex use-case and requires higher-level + * work by the delegate. + * + * It should: + * 1) perform a higher level optimization (e.g. using tariff information, and user preferences) + * 2) if a solution can be found, then update the forecast, else return Failure + * 3) notify the appliance to follow the revised schedule + */ +Status DeviceEnergyManagementDelegate::RequestConstraintBasedForecast( + const DataModel::DecodableList & constraints) +{ + Status status = Status::UnsupportedCommand; // Status::Success; + // TODO: implement the behaviour above + return status; +} + +// ------------------------------------------------------------------ +// Get attribute methods +ESATypeEnum DeviceEnergyManagementDelegate::GetESAType() +{ + return mEsaType; +} + +bool DeviceEnergyManagementDelegate::GetESACanGenerate() +{ + return mEsaCanGenerate; +} + +ESAStateEnum DeviceEnergyManagementDelegate::GetESAState() +{ + return mEsaState; +} + +int64_t DeviceEnergyManagementDelegate::GetAbsMinPower() +{ + return mAbsMinPower; +} + +int64_t DeviceEnergyManagementDelegate::GetAbsMaxPower() +{ + return mAbsMaxPower; +} + +PowerAdjustmentCapability::TypeInfo::Type DeviceEnergyManagementDelegate::GetPowerAdjustmentCapability() +{ + return mPowerAdjustmentCapability; +} + +DataModel::Nullable DeviceEnergyManagementDelegate::GetForecast() +{ + return mForecast; +} + +// ------------------------------------------------------------------ +// Set attribute methods + +CHIP_ERROR DeviceEnergyManagementDelegate::SetESAType(ESATypeEnum newValue) +{ + ESATypeEnum oldValue = mEsaType; + + if (newValue >= ESATypeEnum::kUnknownEnumValue) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mEsaType = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mEsaType updated to %d", static_cast(mEsaType)); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAType::Id); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementDelegate::SetESACanGenerate(bool newValue) +{ + bool oldValue = mEsaCanGenerate; + + mEsaCanGenerate = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mEsaCanGenerate updated to %d", static_cast(mEsaCanGenerate)); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESACanGenerate::Id); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementDelegate::SetESAState(ESAStateEnum newValue) +{ + ESAStateEnum oldValue = mEsaState; + + if (newValue >= ESAStateEnum::kUnknownEnumValue) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mEsaState = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mEsaState updated to %d", static_cast(mEsaState)); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAState::Id); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMinPower(int64_t newValue) +{ + int64_t oldValue = mAbsMinPower; + + mAbsMinPower = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mAbsMinPower updated to %d", static_cast(mAbsMinPower)); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, AbsMinPower::Id); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMaxPower(int64_t newValue) +{ + int64_t oldValue = mAbsMaxPower; + + mAbsMaxPower = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mAbsMaxPower updated to %d", static_cast(mAbsMaxPower)); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, AbsMaxPower::Id); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +DeviceEnergyManagementDelegate::SetPowerAdjustmentCapability(PowerAdjustmentCapability::TypeInfo::Type powerAdjustmentCapability) +{ + // TODO see Issue #31147 + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementDelegate::SetForecast(DataModel::Nullable forecast) +{ + // TODO see Issue #31147 + + return CHIP_NO_ERROR; +} diff --git a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp new file mode 100644 index 00000000000000..c31e0624e4c743 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2023 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 + +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; + +CHIP_ERROR DeviceEnergyManagementManager::Init() +{ + return Instance::Init(); +} + +void DeviceEnergyManagementManager::Shutdown() +{ + Instance::Shutdown(); +} diff --git a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp index da21a51cf7eb5d..fe51c9da664b6d 100644 --- a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp @@ -33,7 +33,7 @@ CHIP_ERROR EVSEManufacturer::Init() EnergyEvseDelegate * dg = GetEvseManufacturer()->GetDelegate(); if (dg == nullptr) { - ChipLogError(AppServer, "Delegate is not initialized"); + ChipLogError(AppServer, "EVSE Delegate is not initialized"); return CHIP_ERROR_UNINITIALIZED; } diff --git a/examples/energy-management-app/linux/BUILD.gn b/examples/energy-management-app/linux/BUILD.gn index 8597caabfc35b9..8fb53878129c60 100644 --- a/examples/energy-management-app/linux/BUILD.gn +++ b/examples/energy-management-app/linux/BUILD.gn @@ -36,6 +36,8 @@ config("includes") { executable("chip-energy-management-app") { sources = [ + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", diff --git a/examples/energy-management-app/linux/main.cpp b/examples/energy-management-app/linux/main.cpp index faf7651875fa94..23ec97e267f45d 100644 --- a/examples/energy-management-app/linux/main.cpp +++ b/examples/energy-management-app/linux/main.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -35,8 +36,10 @@ using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; -static std::unique_ptr gDelegate; -static std::unique_ptr gInstance; +static std::unique_ptr gEvseDelegate; +static std::unique_ptr gEvseInstance; +static std::unique_ptr gDEMDelegate; +static std::unique_ptr gDEMInstance; static std::unique_ptr gEvseManufacturer; EVSEManufacturer * EnergyEvse::GetEvseManufacturer() @@ -44,58 +47,173 @@ EVSEManufacturer * EnergyEvse::GetEvseManufacturer() return gEvseManufacturer.get(); } -void ApplicationInit() +/* + * @brief Creates a Delegate and Instance for DEM + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR DeviceEnergyManagementInit() +{ + if (gDEMDelegate || gDEMInstance) + { + ChipLogError(AppServer, "DEM Instance or Delegate already exist."); + return CHIP_ERROR_INCORRECT_STATE; + } + + gDEMDelegate = std::make_unique(); + if (!gDEMDelegate) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementDelegate"); + return CHIP_ERROR_NO_MEMORY; + } + + /* Manufacturer may optionally not support all features, commands & attributes */ + gDEMInstance = std::make_unique( + EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate, + BitMask( + DeviceEnergyManagement::Feature::kPowerForecastReporting, DeviceEnergyManagement::Feature::kStateForecastReporting, + DeviceEnergyManagement::Feature::kPowerAdjustment, DeviceEnergyManagement::Feature::kForecastAdjustment), + BitMask( + DeviceEnergyManagement::OptionalCommands::kSupportsModifyForecastRequest, + DeviceEnergyManagement::OptionalCommands::kSupportsRequestConstraintBasedForecast)); + + if (!gDEMInstance) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementManager"); + gDEMDelegate.reset(); + return CHIP_ERROR_NO_MEMORY; + } + + CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gDEMInstance"); + gDEMInstance.reset(); + gDEMDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceEnergyManagementShutdown() +{ + /* Do this in the order Instance first, then delegate + * Ensure we call the Instance->Shutdown to free attribute & command handlers first + */ + if (gDEMInstance) + { + /* deregister attribute & command handlers */ + gDEMInstance->Shutdown(); + gDEMInstance.reset(); + } + if (gDEMDelegate) + { + gDEMDelegate.reset(); + } + return CHIP_NO_ERROR; +} + +/* + * @brief Creates a Delegate and Instance for EVSE cluster + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR EnergyEvseInit() { CHIP_ERROR err; - if (gDelegate || gInstance || gEvseManufacturer) + if (gEvseDelegate || gEvseInstance) { - ChipLogError(AppServer, "EVSE Instance or Delegate, EvseManufacturer already exist."); - return; + ChipLogError(AppServer, "EVSE Instance or Delegate already exist."); + return CHIP_ERROR_INCORRECT_STATE; } - gDelegate = std::make_unique(); - if (!gDelegate) + gEvseDelegate = std::make_unique(); + if (!gEvseDelegate) { ChipLogError(AppServer, "Failed to allocate memory for EnergyEvseDelegate"); - return; + return CHIP_ERROR_NO_MEMORY; } /* Manufacturer may optionally not support all features, commands & attributes */ - gInstance = std::make_unique( - EndpointId(ENERGY_EVSE_ENDPOINT), *gDelegate, + gEvseInstance = std::make_unique( + EndpointId(ENERGY_EVSE_ENDPOINT), *gEvseDelegate, BitMask(EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge, EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting, EnergyEvse::Feature::kV2x), - BitMask(OptionalAttributes::kSupportsUserMaximumChargingCurrent, - OptionalAttributes::kSupportsRandomizationWindow, - OptionalAttributes::kSupportsApproximateEvEfficiency), - BitMask(OptionalCommands::kSupportsStartDiagnostics)); + BitMask(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent, + EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow, + EnergyEvse::OptionalAttributes::kSupportsApproximateEvEfficiency), + BitMask(EnergyEvse::OptionalCommands::kSupportsStartDiagnostics)); - if (!gInstance) + if (!gEvseInstance) { ChipLogError(AppServer, "Failed to allocate memory for EnergyEvseManager"); - gDelegate.reset(); - return; + gEvseDelegate.reset(); + return CHIP_ERROR_NO_MEMORY; } - err = gInstance->Init(); /* Register Attribute & Command handlers */ + err = gEvseInstance->Init(); /* Register Attribute & Command handlers */ if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "Init failed on gInstance"); - gInstance.reset(); - gDelegate.reset(); - return; + ChipLogError(AppServer, "Init failed on gEvseInstance"); + gEvseInstance.reset(); + gEvseDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EnergyEvseShutdown() +{ + /* Do this in the order Instance first, then delegate + * Ensure we call the Instance->Shutdown to free attribute & command handlers first + */ + if (gEvseInstance) + { + /* deregister attribute & command handlers */ + gEvseInstance->Shutdown(); + gEvseInstance.reset(); } - /* Now create EVSEManufacturer*/ - gEvseManufacturer = std::make_unique(gInstance.get()); + if (gEvseDelegate) + { + gEvseDelegate.reset(); + } + + return CHIP_NO_ERROR; +} + +/* + * @brief Creates a EVSEManufacturer class to hold the EVSE & DEM clusters + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR EVSEManufacturerInit() +{ + CHIP_ERROR err; + + if (gEvseManufacturer) + { + ChipLogError(AppServer, "EvseManufacturer already exist."); + return CHIP_ERROR_INCORRECT_STATE; + } + + /* Now create EVSEManufacturer */ + // TODO this takes just the EVSE Instance for now, but will need the DEM adding + gEvseManufacturer = std::make_unique(gEvseInstance.get()); if (!gEvseManufacturer) { ChipLogError(AppServer, "Failed to allocate memory for EvseManufacturer"); - gInstance.reset(); - gDelegate.reset(); - return; + return CHIP_ERROR_NO_MEMORY; } /* Call Manufacturer specific init */ @@ -104,8 +222,41 @@ void ApplicationInit() { ChipLogError(AppServer, "Init failed on gEvseManufacturer"); gEvseManufacturer.reset(); - gInstance.reset(); - gDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EVSEManufacturerShutdown() +{ + if (gEvseManufacturer) + { + /* Shutdown the EVSEManufacturer */ + gEvseManufacturer->Shutdown(); + gEvseManufacturer.reset(); + } + + return CHIP_NO_ERROR; +} + +void ApplicationInit() +{ + if (DeviceEnergyManagementInit() != CHIP_NO_ERROR) + { + return; + } + + if (EnergyEvseInit() != CHIP_NO_ERROR) + { + DeviceEnergyManagementShutdown(); + return; + } + + if (EVSEManufacturerInit() != CHIP_NO_ERROR) + { + DeviceEnergyManagementShutdown(); + EnergyEvseShutdown(); return; } } @@ -114,13 +265,10 @@ void ApplicationShutdown() { ChipLogDetail(AppServer, "Energy Management App: ApplicationShutdown()"); - /* Shutdown the EVSEManufacturer*/ - if (gEvseManufacturer) - gEvseManufacturer->Shutdown(); - - /* Shutdown the Instance - deregister attribute & command handler */ - if (gInstance) - gInstance->Shutdown(); + /* Shutdown in reverse order that they were created */ + EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */ + EnergyEvseShutdown(); /* Free the EnergyEvse */ + DeviceEnergyManagementShutdown(); /* Free the DEM */ } int main(int argc, char * argv[]) diff --git a/examples/shell/shell_common/BUILD.gn b/examples/shell/shell_common/BUILD.gn index a54df29c798955..28b26af3ae211f 100644 --- a/examples/shell/shell_common/BUILD.gn +++ b/examples/shell/shell_common/BUILD.gn @@ -65,10 +65,13 @@ static_library("shell_common") { sources += [ "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/device-energy-management-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", ] diff --git a/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp new file mode 100644 index 00000000000000..bfe3cac5f2e89e --- /dev/null +++ b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * + * 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 "device-energy-management-server.h" + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; +using namespace chip::app::Clusters::DeviceEnergyManagement::Attributes; + +using chip::Protocols::InteractionModel::Status; + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +CHIP_ERROR Instance::Init() +{ + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->RegisterCommandHandler(this)); + VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INCORRECT_STATE); + + return CHIP_NO_ERROR; +} + +void Instance::Shutdown() +{ + InteractionModelEngine::GetInstance()->UnregisterCommandHandler(this); + unregisterAttributeAccessOverride(this); +} + +bool Instance::HasFeature(Feature aFeature) const +{ + return mFeature.Has(aFeature); +} + +bool Instance::SupportsOptCmd(OptionalCommands aOptionalCmds) const +{ + return mOptionalCmds.Has(aOptionalCmds); +} + +// AttributeAccessInterface +CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + switch (aPath.mAttributeId) + { + case ESAType::Id: + return aEncoder.Encode(mDelegate.GetESAType()); + case ESACanGenerate::Id: + return aEncoder.Encode(mDelegate.GetESACanGenerate()); + case ESAState::Id: + return aEncoder.Encode(mDelegate.GetESAState()); + case AbsMinPower::Id: + return aEncoder.Encode(mDelegate.GetAbsMinPower()); + case AbsMaxPower::Id: + return aEncoder.Encode(mDelegate.GetAbsMaxPower()); + case PowerAdjustmentCapability::Id: + /* PA - PowerAdjustment */ + if (!HasFeature(Feature::kPowerAdjustment)) + { + return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); + } + return aEncoder.Encode(mDelegate.GetPowerAdjustmentCapability()); + case Forecast::Id: + /* PFR | SFR - Power Forecast Reporting or State Forecast Reporting */ + if (!HasFeature(Feature::kPowerForecastReporting) && !HasFeature(Feature::kStateForecastReporting)) + { + return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); + } + return aEncoder.Encode(mDelegate.GetForecast()); + /* FeatureMap - is held locally */ + case FeatureMap::Id: + return aEncoder.Encode(mFeature); + } + + /* Allow all other unhandled attributes to fall through to Ember */ + return CHIP_NO_ERROR; +} + +// CommandHandlerInterface +CHIP_ERROR Instance::EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) +{ + using namespace Commands; + + if (HasFeature(Feature::kPowerAdjustment)) + { + for (auto && cmd : { + PowerAdjustRequest::Id, + CancelPowerAdjustRequest::Id, + }) + { + VerifyOrExit(callback(cmd, context) == Loop::Continue, /**/); + } + } + + if (HasFeature(Feature::kForecastAdjustment)) + { + for (auto && cmd : { + StartTimeAdjustRequest::Id, + PauseRequest::Id, + ResumeRequest::Id, + }) + { + VerifyOrExit(callback(cmd, context) == Loop::Continue, /**/); + } + } + + if (SupportsOptCmd(OptionalCommands::kSupportsModifyForecastRequest)) + { + VerifyOrExit(callback(ModifyForecastRequest::Id, context) == Loop::Continue, /**/); + } + + if (SupportsOptCmd(OptionalCommands::kSupportsRequestConstraintBasedForecast)) + { + VerifyOrExit(callback(RequestConstraintBasedForecast::Id, context) == Loop::Continue, /**/); + } + +exit: + return CHIP_NO_ERROR; +} + +void Instance::InvokeCommand(HandlerContext & handlerContext) +{ + using namespace Commands; + + switch (handlerContext.mRequestPath.mCommandId) + { + case PowerAdjustRequest::Id: + if (!HasFeature(Feature::kPowerAdjustment)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandlePowerAdjustRequest(ctx, commandData); }); + } + return; + case CancelPowerAdjustRequest::Id: + if (!HasFeature(Feature::kPowerAdjustment)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleCancelPowerAdjustRequest(ctx, commandData); }); + } + return; + case StartTimeAdjustRequest::Id: + if (!HasFeature(Feature::kForecastAdjustment)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleStartTimeAdjustRequest(ctx, commandData); }); + } + return; + case PauseRequest::Id: + if (!HasFeature(Feature::kForecastAdjustment)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandlePauseRequest(ctx, commandData); }); + } + return; + case ResumeRequest::Id: + if (!HasFeature(Feature::kForecastAdjustment)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleResumeRequest(ctx, commandData); }); + } + return; + case ModifyForecastRequest::Id: + if (!SupportsOptCmd(OptionalCommands::kSupportsModifyForecastRequest)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleModifyForecastRequest(ctx, commandData); }); + } + return; + case RequestConstraintBasedForecast::Id: + if (!SupportsOptCmd(OptionalCommands::kSupportsRequestConstraintBasedForecast)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + } + else + { + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleRequestConstraintBasedForecast(ctx, commandData); }); + } + return; + } +} + +void Instance::HandlePowerAdjustRequest(HandlerContext & ctx, const Commands::PowerAdjustRequest::DecodableType & commandData) +{ + int64_t power = commandData.power; + uint32_t durationSec = commandData.duration; + bool validArgs = false; + Status status = Status::Success; + + PowerAdjustmentCapability::TypeInfo::Type powerAdjustmentCapability; + powerAdjustmentCapability = mDelegate.GetPowerAdjustmentCapability(); + + if (powerAdjustmentCapability.IsNull()) + { + ChipLogError(Zcl, "DEM: powerAdjustmentCapability IsNull"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + /* PowerAdjustmentCapability is a list - so iterate through checking if the command is within one of the offers */ + for (auto pas : powerAdjustmentCapability.Value()) + { + if ((power >= pas.minPower) && (durationSec >= pas.minDuration) && (power <= pas.maxPower) && + (durationSec <= pas.maxDuration)) + { + ChipLogProgress(Zcl, "DEM: Good PowerAdjustment args"); + validArgs = true; + break; + } + } + + if (!validArgs) + { + ChipLogError(Zcl, "DEM: invalid request range"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + ChipLogProgress(Zcl, "DEM: Good PowerAdjustRequest() args."); + + status = mDelegate.PowerAdjustRequest(power, durationSec); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: Failed to PowerAdjustRequest() args."); + } +} + +void Instance::HandleCancelPowerAdjustRequest(HandlerContext & ctx, + const Commands::CancelPowerAdjustRequest::DecodableType & commandData) +{ + Status status = Status::Success; + ESAStateEnum esaStatus; + + /* Check that the ESA state is PowerAdjustActive */ + esaStatus = mDelegate.GetESAState(); + if (ESAStateEnum::kPowerAdjustActive != esaStatus) + { + ChipLogError(Zcl, "DEM: kPowerAdjustActive != esaStatus"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + status = mDelegate.CancelPowerAdjustRequest(); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: Failed to CancelPowerAdjustRequest()"); + return; + } +} + +void Instance::HandleStartTimeAdjustRequest(HandlerContext & ctx, + const Commands::StartTimeAdjustRequest::DecodableType & commandData) +{ + Status status = Status::Success; + uint32_t earliestStartTimeEpoch = 0; + uint32_t latestEndTimeEpoch = 0; + uint32_t requestedStartTimeEpoch = commandData.requestedStartTime; + uint32_t duration; + + DataModel::Nullable forecastNullable = mDelegate.GetForecast(); + + if (forecastNullable.IsNull()) + { + ChipLogError(Zcl, "DEM: Forecast is Null"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + if (ESAStateEnum::kUserOptOut == mDelegate.GetESAState()) + { + ChipLogError(Zcl, "DEM: ESAState = kUserOptOut"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + /* Temporary variable to save calling .Value() on forecastNullable */ + auto & forecast = forecastNullable.Value(); + + /** + * If the RequestedStartTime value resulted in a time shift which is + * outside the time constraints of EarliestStartTime and + * LatestEndTime, then the command SHALL be rejected with CONSTRAINT_ERROR; + * in other failure scenarios the command SHALL be rejected with FAILURE + */ + /* earliestStartTime is optional based on the StartTimeAdjust (STA) feature AND is nullable */ + if (!(forecast.earliestStartTime.HasValue()) || !(forecast.latestEndTime.HasValue())) + { + /* These should have values, since this command requires STA feature and these are mandatory for that */ + ChipLogError(Zcl, "DEM: EarliestStartTime / LatestEndTime do not have values"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + /* Temporary variable to save keep calling .Value() on the Optional element */ + DataModel::Nullable & earliestStartTimeNullable = forecast.earliestStartTime.Value(); + /* Latest End Time is optional & cannot be null - unlike earliestStartTime! */ + latestEndTimeEpoch = forecast.latestEndTime.Value(); + + if (earliestStartTimeNullable.IsNull()) + { + System::Clock::Milliseconds64 cTMs; + CHIP_ERROR err = System::SystemClock().GetClock_RealTimeMS(cTMs); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "DEM: Unable to get current time - err:%" CHIP_ERROR_FORMAT, err.Format()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + auto unixEpoch = std::chrono::duration_cast(cTMs).count(); + uint32_t chipEpoch = 0; + if (!UnixEpochToChipEpochTime(unixEpoch, chipEpoch)) + { + ChipLogError(Zcl, "DEM: unable to convert Unix Epoch time to Matter Epoch Time"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + /* Null means - We can start immediately */ + earliestStartTimeEpoch = chipEpoch; /* NOW */ + } + else + { + earliestStartTimeEpoch = earliestStartTimeNullable.Value(); + } + + duration = forecast.endTime - forecast.startTime; // the current entire forecast duration + if (requestedStartTimeEpoch < earliestStartTimeEpoch) + { + ChipLogError(Zcl, "DEM: Bad requestedStartTime %ld, earlier than earliestStartTime %ld.", + static_cast(requestedStartTimeEpoch), + static_cast(earliestStartTimeEpoch)); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + if ((requestedStartTimeEpoch + duration) > latestEndTimeEpoch) + { + ChipLogError(Zcl, "DEM: Bad requestedStartTimeEpoch + duration %ld, later than latestEndTime %ld.", + static_cast(requestedStartTimeEpoch + duration), + static_cast(latestEndTimeEpoch)); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + ChipLogProgress(Zcl, "DEM: Good requestedStartTimeEpoch %ld.", static_cast(requestedStartTimeEpoch)); + status = mDelegate.StartTimeAdjustRequest(requestedStartTimeEpoch); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: StartTimeAdjustRequest(%ld) FAILURE", static_cast(requestedStartTimeEpoch)); + return; + } +} + +void Instance::HandlePauseRequest(HandlerContext & ctx, const Commands::PauseRequest::DecodableType & commandData) +{ + Status status = Status::Success; + CHIP_ERROR err = CHIP_NO_ERROR; + DataModel::Nullable forecast = mDelegate.GetForecast(); + + uint32_t duration = commandData.duration; + + if (forecast.IsNull()) + { + ChipLogError(Zcl, "DEM: Forecast is Null"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + if (ESAStateEnum::kUserOptOut == mDelegate.GetESAState()) + { + ChipLogError(Zcl, "DEM: ESAState = kUserOptOut"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + /* value SHALL be between the MinPauseDuration and MaxPauseDuration indicated in the + ActiveSlotNumber index in the Slots list in the Forecast. + */ + uint16_t activeSlotNumber; + if (forecast.Value().activeSlotNumber.IsNull()) + { + ChipLogError(Zcl, "DEM: activeSlotNumber Is Null"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + activeSlotNumber = forecast.Value().activeSlotNumber.Value(); + if (activeSlotNumber >= forecast.Value().slots.size()) + { + ChipLogError(Zcl, "DEM: Bad activeSlotNumber %d , size()=%d.", activeSlotNumber, + static_cast(forecast.Value().slots.size())); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + if (!forecast.Value().slots[activeSlotNumber].slotIsPauseable) + { + ChipLogError(Zcl, "DEM: activeSlotNumber %d is NOT pauseable.", activeSlotNumber); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + if ((duration < forecast.Value().slots[activeSlotNumber].minPauseDuration) && + (duration > forecast.Value().slots[activeSlotNumber].maxPauseDuration)) + { + ChipLogError(Zcl, "DEM: out of range pause duration %ld", static_cast(duration)); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + + err = mDelegate.SetESAState(ESAStateEnum::kPaused); + if (CHIP_NO_ERROR != err) + { + ChipLogError(Zcl, "DEM: SetESAState(paused) FAILURE"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + status = mDelegate.PauseRequest(duration); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: mDelegate.PauseRequest(%ld) FAILURE", static_cast(duration)); + return; + } +} + +void Instance::HandleResumeRequest(HandlerContext & ctx, const Commands::ResumeRequest::DecodableType & commandData) +{ + Status status = Status::Success; + DataModel::Nullable forecast = mDelegate.GetForecast(); + + if (ESAStateEnum::kPaused != mDelegate.GetESAState()) + { + ChipLogError(Zcl, "DEM: ESAState not Paused."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + status = mDelegate.ResumeRequest(); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: mDelegate.ResumeRequest() FAILURE"); + return; + } +} + +void Instance::HandleModifyForecastRequest(HandlerContext & ctx, const Commands::ModifyForecastRequest::DecodableType & commandData) +{ + Status status = Status::Success; + uint32_t forecastId = commandData.forecastId; + DataModel::Nullable forecast; + + if (ESAStateEnum::kUserOptOut == mDelegate.GetESAState()) + { + ChipLogError(Zcl, "DEM: ESAState = kUserOptOut"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + forecast = mDelegate.GetForecast(); + if (forecast.IsNull()) + { + ChipLogError(Zcl, "DEM: Forecast is Null"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + DataModel::DecodableList slotAdjustments = commandData.slotAdjustments; + status = mDelegate.ModifyForecastRequest(forecastId, slotAdjustments); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: mDelegate.ModifyForecastRequest() FAILURE"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } +} + +void Instance::HandleRequestConstraintBasedForecast(HandlerContext & ctx, + const Commands::RequestConstraintBasedForecast::DecodableType & commandData) +{ + Status status = Status::Success; + + if (ESAStateEnum::kUserOptOut == mDelegate.GetESAState()) + { + ChipLogError(Zcl, "DEM: ESAState = kUserOptOut"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } + + status = mDelegate.RequestConstraintBasedForecast(commandData.constraints); + if (status != Status::Success) + { + ChipLogError(Zcl, "DEM: mDelegate.commandData.constraints() FAILURE"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + return; + } +} + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip + +void MatterDeviceEnergyManagementPluginServerInitCallback() {} diff --git a/src/app/clusters/device-energy-management-server/device-energy-management-server.h b/src/app/clusters/device-energy-management-server/device-energy-management-server.h new file mode 100644 index 00000000000000..7ab6a8aa60f306 --- /dev/null +++ b/src/app/clusters/device-energy-management-server/device-energy-management-server.h @@ -0,0 +1,214 @@ +/* + * + * Copyright (c) 2023 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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +using namespace chip::app::Clusters::DeviceEnergyManagement::Attributes; + +using chip::Protocols::InteractionModel::Status; + +class Delegate +{ +public: + virtual ~Delegate() = default; + + void SetEndpointId(EndpointId aEndpoint) { mEndpointId = aEndpoint; } + + /** + * @brief Delegate should implement a handler to begin to adjust client power + * consumption/generation to the level requested. + * + * @param power Milli-Watts the ESA SHALL use during the adjustment period. + * @param duration The duration that the ESA SHALL maintain the requested power for. + * @return Success if the adjustment is accepted; otherwise the command SHALL be rejected with appropriate error. + */ + virtual Status PowerAdjustRequest(const int64_t power, const uint32_t duration) = 0; + + /** + * @brief Delegate SHALL make the ESA end the active power adjustment session & return to normal (or idle) power levels. + * The ESA SHALL also generate an PowerAdjustEnd Event and the ESAState SHALL be restored to Online. + * + * @return It should report SUCCESS if successful and FAILURE otherwise. + */ + virtual Status CancelPowerAdjustRequest() = 0; + + /** + * @brief Delegate for the ESA SHALL update its Forecast attribute with the RequestedStartTime including a new ForecastId. + * + * If the ESA supports ForecastAdjustment, and the ESAState is not UserOptOut and the RequestedStartTime is after + * the EarliestStartTime and the resulting EndTime is before the LatestEndTime, then ESA SHALL accept the request + * to modify the Start Time. + * A client can estimate the entire Forecast sequence duration by computing the EndTime - StartTime fields from the + * Forecast attribute, and therefore avoid scheduling the start time too late. + * + * @param requestedStartTime The requested start time in UTC that the client would like the appliance to shift its power + * forecast to. + * @return Success if the StartTime in the Forecast is updated, otherwise the command SHALL be rejected with appropriate + * IM_Status. + */ + virtual Status StartTimeAdjustRequest(const uint32_t requestedStartTime) = 0; + + /** + * @brief Delegate handler for PauseRequest command + * + * If the ESA supports FA and the SlotIsPauseable field is true in the ActiveSlotNumber + * index in the Slots list, and the ESAState is not UserOptOut then the ESA SHALL allow its current + * operation to be Paused. + * + * During this state the ESA SHALL not consume or produce significant power (other than required to keep its + * basic control system operational). + * + * @param duration Duration that the ESA SHALL be paused for. + * @return Success if the ESA is paused, otherwise returns other IM_Status. + */ + virtual Status PauseRequest(const uint32_t duration) = 0; + + /** + * @brief Delegate handler for ResumeRequest command + * + * If the ESA supports FA and it is currently Paused then the ESA SHALL resume its operation. + * The ESA SHALL also generate a Resumed Event and the ESAState SHALL be updated accordingly to + * reflect its current state. + * + * @return Success if the ESA is resumed, otherwise returns other IM_Status. + */ + virtual Status ResumeRequest() = 0; + + /** + * @brief Delegate handler for ModifyForecastRequest + * + * If the ESA supports FA, and the ESAState is not UserOptOut it SHALL attempt to adjust its power forecast. + * This allows a one or more modifications in a single command by sending a list of modifications (one for each 'slot'). + * Attempts to modify slots which have already past, SHALL result in the entire command being rejected. + * If the ESA accepts the requested Forecast then it SHALL update its Forecast attribute (incrementing its ForecastId) + * and run the revised Forecast as its new intended operation. + * + * @param forecastId Indicates the ESA ForecastId that is to be modified. + * @param slotAdjustments List of adjustments to be applied to the ESA, corresponding to the expected ESA forecastId. + * @return Success if the entire list of SlotAdjustmentStruct are accepted, otherwise the command + * SHALL be rejected returning other IM_Status. + */ + virtual Status ModifyForecastRequest(const uint32_t forecastId, + const DataModel::DecodableList & slotAdjustments) = 0; + + /** + * @brief Delegate handler for RequestConstraintBasedForecast + * + * The ESA SHALL inspect the requested power limits to ensure that there are no overlapping elements. The ESA + * manufacturer may also reject the request if it could cause the user’s preferences to be breached (e.g. may + * cause the home to be too hot or too cold, or a battery to be insufficiently charged). + * If the ESA can meet the requested power limits, it SHALL regenerate a new Power Forecast with a new ForecastId. + * + * @param constraints Sequence of turn up/down power requests that the ESA is being asked to constrain its operation within. + * @return Success if successful, otherwise the command SHALL be rejected returning other IM_Status. + */ + virtual Status + RequestConstraintBasedForecast(const DataModel::DecodableList & constraints) = 0; + + // ------------------------------------------------------------------ + // Get attribute methods + virtual ESATypeEnum GetESAType() = 0; + virtual bool GetESACanGenerate() = 0; + virtual ESAStateEnum GetESAState() = 0; + virtual int64_t GetAbsMinPower() = 0; + virtual int64_t GetAbsMaxPower() = 0; + virtual PowerAdjustmentCapability::TypeInfo::Type GetPowerAdjustmentCapability() = 0; + virtual DataModel::Nullable GetForecast() = 0; + + // ------------------------------------------------------------------ + // Set attribute methods + virtual CHIP_ERROR SetESAType(ESATypeEnum) = 0; + virtual CHIP_ERROR SetESACanGenerate(bool) = 0; + virtual CHIP_ERROR SetESAState(ESAStateEnum) = 0; + virtual CHIP_ERROR SetAbsMinPower(int64_t) = 0; + virtual CHIP_ERROR SetAbsMaxPower(int64_t) = 0; + virtual CHIP_ERROR SetPowerAdjustmentCapability(PowerAdjustmentCapability::TypeInfo::Type) = 0; + virtual CHIP_ERROR SetForecast(DataModel::Nullable) = 0; + +protected: + EndpointId mEndpointId = 0; +}; + +enum class OptionalCommands : uint32_t +{ + kSupportsModifyForecastRequest = 0x1, + kSupportsRequestConstraintBasedForecast = 0x2 +}; + +class Instance : public AttributeAccessInterface, public CommandHandlerInterface +{ +public: + Instance(EndpointId aEndpointId, Delegate & aDelegate, Feature aFeature, OptionalCommands aOptionalCmds) : + AttributeAccessInterface(MakeOptional(aEndpointId), Id), CommandHandlerInterface(MakeOptional(aEndpointId), Id), + mDelegate(aDelegate), mFeature(aFeature), mOptionalCmds(aOptionalCmds) + { + /* set the base class delegates endpointId */ + mDelegate.SetEndpointId(aEndpointId); + } + + ~Instance() { Shutdown(); } + + CHIP_ERROR Init(); + void Shutdown(); + + bool HasFeature(Feature aFeature) const; + bool SupportsOptCmd(OptionalCommands aOptionalCmds) const; + +private: + Delegate & mDelegate; + BitMask mFeature; + BitMask mOptionalCmds; + + // AttributeAccessInterface + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + // NOTE there are no writable attributes + + // CommandHandlerInterface + void InvokeCommand(HandlerContext & handlerContext) override; + CHIP_ERROR EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) override; + + void HandlePowerAdjustRequest(HandlerContext & ctx, const Commands::PowerAdjustRequest::DecodableType & commandData); + void HandleCancelPowerAdjustRequest(HandlerContext & ctx, + const Commands::CancelPowerAdjustRequest::DecodableType & commandData); + void HandleStartTimeAdjustRequest(HandlerContext & ctx, const Commands::StartTimeAdjustRequest::DecodableType & commandData); + void HandlePauseRequest(HandlerContext & ctx, const Commands::PauseRequest::DecodableType & commandData); + void HandleResumeRequest(HandlerContext & ctx, const Commands::ResumeRequest::DecodableType & commandData); + void HandleModifyForecastRequest(HandlerContext & ctx, const Commands::ModifyForecastRequest::DecodableType & commandData); + void HandleRequestConstraintBasedForecast(HandlerContext & ctx, + const Commands::RequestConstraintBasedForecast::DecodableType & commandData); +}; + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/energy-evse-server/energy-evse-server.cpp b/src/app/clusters/energy-evse-server/energy-evse-server.cpp index bc07ba07eef55a..019aead77c24a8 100644 --- a/src/app/clusters/energy-evse-server/energy-evse-server.cpp +++ b/src/app/clusters/energy-evse-server/energy-evse-server.cpp @@ -126,6 +126,10 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu return aEncoder.Encode(mDelegate.GetSessionEnergyCharged()); case SessionEnergyDischarged::Id: return aEncoder.Encode(mDelegate.GetSessionEnergyDischarged()); + + /* FeatureMap - is held locally */ + case FeatureMap::Id: + return aEncoder.Encode(mFeature); } /* Allow all other unhandled attributes to fall through to Ember */ return CHIP_NO_ERROR; diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index a39d0a58b128f9..b071fd42c77cb8 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -178,7 +178,42 @@ ], "Bridged Device Basic Information": ["ProductAppearance"], "Descriptor": ["ClusterRevision"], - "Device Energy Management": ["Forecast"], + "Device Energy Management": [ + "ESAType", + "ESACanGenerate", + "ESAState", + "AbsMinPower", + "AbsMaxPower", + "PowerAdjustmentCapability", + "Forecast", + "FeatureMap" + ], + "Energy EVSE": [ + "State", + "SupplyState", + "FaultState", + "ChargingEnabledUntil", + "DischargingEnabledUntil", + "CircuitCapacity", + "MinimumChargeCurrent", + "MaximumChargeCurrent", + "MaximumDischargeCurrent", + "UserMaximumChargeCurrent", + "RandomizationDelayWindow", + "NextChargeStartTime", + "NextChargeTargetTime", + "NextChargeRequiredEnergy", + "NextChargeTargetSoC", + "ApproximateEVEfficiency", + "StateOfCharge", + "BatteryCapacity", + "VehicleID", + "SessionID", + "SessionDuration", + "SessionEnergyCharged", + "SessionEnergyDischarged", + "FeatureMap" + ], "Ethernet Network Diagnostics": [ "PHYRate", "FullDuplex", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 21f13fb7f6d14b..c645c66e91fc5c 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -176,7 +176,42 @@ ], "Bridged Device Basic Information": ["ProductAppearance"], "Descriptor": ["ClusterRevision"], - "Device Energy Management": ["Forecast"], + "Device Energy Management": [ + "ESAType", + "ESACanGenerate", + "ESAState", + "AbsMinPower", + "AbsMaxPower", + "PowerAdjustmentCapability", + "Forecast", + "FeatureMap" + ], + "Energy EVSE": [ + "State", + "SupplyState", + "FaultState", + "ChargingEnabledUntil", + "DischargingEnabledUntil", + "CircuitCapacity", + "MinimumChargeCurrent", + "MaximumChargeCurrent", + "MaximumDischargeCurrent", + "UserMaximumChargeCurrent", + "RandomizationDelayWindow", + "NextChargeStartTime", + "NextChargeTargetTime", + "NextChargeRequiredEnergy", + "NextChargeTargetSoC", + "ApproximateEVEfficiency", + "StateOfCharge", + "BatteryCapacity", + "VehicleID", + "SessionID", + "SessionDuration", + "SessionEnergyCharged", + "SessionEnergyDischarged", + "FeatureMap" + ], "Ethernet Network Diagnostics": [ "PHYRate", "FullDuplex", diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index 2d66ab991824ce..6f3fba5935f84d 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -10400,192 +10400,6 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value) namespace DeviceEnergyManagement { namespace Attributes { -namespace ESAType { - -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESATypeEnum * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESATypeEnum value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); -} - -} // namespace ESAType - -namespace ESACanGenerate { - -EmberAfStatus Get(chip::EndpointId endpoint, bool * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, bool value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_BOOLEAN_ATTRIBUTE_TYPE); -} - -} // namespace ESACanGenerate - -namespace ESAState { - -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESAStateEnum * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESAStateEnum value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); -} - -} // namespace ESAState - -namespace AbsMinPower { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_POWER_MW_ATTRIBUTE_TYPE); -} - -} // namespace AbsMinPower - -namespace AbsMaxPower { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_POWER_MW_ATTRIBUTE_TYPE); -} - -} // namespace AbsMaxPower - -namespace FeatureMap { - -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); -} - -} // namespace FeatureMap - namespace ClusterRevision { EmberAfStatus Get(chip::EndpointId endpoint, uint16_t * value) @@ -10623,65 +10437,11 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value) namespace EnergyEvse { namespace Attributes { -namespace State { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::StateEnum value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, - const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace State - -namespace SupplyState { +namespace NumberOfWeeklyTargets { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::SupplyStateEnum * value) +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); @@ -10693,9 +10453,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::Su *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::SupplyStateEnum value) +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -10703,16 +10463,16 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::Su Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); } -} // namespace SupplyState +} // namespace NumberOfWeeklyTargets -namespace FaultState { +namespace NumberOfDailyTargets { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::FaultStateEnum * value) +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); @@ -10724,9 +10484,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::Fa *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::FaultStateEnum value) +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -10734,1027 +10494,10 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::Fa Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); -} - -} // namespace FaultState - -namespace ChargingEnabledUntil { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); } -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace ChargingEnabledUntil - -namespace DischargingEnabledUntil { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace DischargingEnabledUntil - -namespace CircuitCapacity { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE); -} - -} // namespace CircuitCapacity - -namespace MinimumChargeCurrent { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE); -} - -} // namespace MinimumChargeCurrent - -namespace MaximumChargeCurrent { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE); -} - -} // namespace MaximumChargeCurrent - -namespace MaximumDischargeCurrent { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE); -} - -} // namespace MaximumDischargeCurrent - -namespace UserMaximumChargeCurrent { - -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE); -} - -} // namespace UserMaximumChargeCurrent - -namespace RandomizationDelayWindow { - -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ELAPSED_S_ATTRIBUTE_TYPE); -} - -} // namespace RandomizationDelayWindow - -namespace NumberOfWeeklyTargets { - -EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); -} - -} // namespace NumberOfWeeklyTargets - -namespace NumberOfDailyTargets { - -EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); -} - -} // namespace NumberOfDailyTargets - -namespace NextChargeStartTime { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace NextChargeStartTime - -namespace NextChargeTargetTime { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_EPOCH_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace NextChargeTargetTime - -namespace NextChargeRequiredEnergy { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace NextChargeRequiredEnergy - -namespace NextChargeTargetSoC { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::Percent value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_PERCENT_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_PERCENT_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace NextChargeTargetSoC - -namespace ApproximateEVEfficiency { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace ApproximateEVEfficiency - -namespace StateOfCharge { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::Percent value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_PERCENT_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_PERCENT_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace StateOfCharge - -namespace BatteryCapacity { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace BatteryCapacity - -namespace VehicleID { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - uint8_t zclString[32 + 1]; - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, zclString, sizeof(zclString)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - size_t length = emberAfStringLength(zclString); - if (length == NumericAttributeTraits::kNullValue) - { - value.SetNull(); - return EMBER_ZCL_STATUS_SUCCESS; - } - auto & span = value.SetNonNull(); - - VerifyOrReturnError(span.size() == 32, EMBER_ZCL_STATUS_INVALID_DATA_TYPE); - memcpy(span.data(), &zclString[1], 32); - span.reduce_size(length); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, chip::CharSpan value) -{ - static_assert(32 < NumericAttributeTraits::kNullValue, "value.size() might be too big"); - VerifyOrReturnError(value.size() <= 32, EMBER_ZCL_STATUS_CONSTRAINT_ERROR); - uint8_t zclString[32 + 1]; - auto length = static_cast(value.size()); - Encoding::Put8(zclString, length); - memcpy(&zclString[1], value.data(), value.size()); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, zclString, ZCL_CHAR_STRING_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - uint8_t zclString[1] = { 0xFF }; - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, zclString, ZCL_CHAR_STRING_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace VehicleID - -namespace SessionID { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT32U_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_INT32U_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace SessionID - -namespace SessionDuration { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ELAPSED_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ELAPSED_S_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace SessionDuration - -namespace SessionEnergyCharged { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace SessionEnergyCharged - -namespace SessionEnergyDischarged { - -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_ENERGY_MWH_ATTRIBUTE_TYPE); -} - -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace SessionEnergyDischarged - -namespace FeatureMap { - -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::EnergyEvse::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - *value = Traits::StorageToWorking(temp); - return status; -} -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::EnergyEvse::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); -} - -} // namespace FeatureMap +} // namespace NumberOfDailyTargets namespace ClusterRevision { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 6cd63bd5d0c76c..2fed842607a66e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -2022,36 +2022,6 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); namespace DeviceEnergyManagement { namespace Attributes { -namespace ESAType { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESATypeEnum * value); // ESATypeEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESATypeEnum value); -} // namespace ESAType - -namespace ESACanGenerate { -EmberAfStatus Get(chip::EndpointId endpoint, bool * value); // boolean -EmberAfStatus Set(chip::EndpointId endpoint, bool value); -} // namespace ESACanGenerate - -namespace ESAState { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESAStateEnum * value); // ESAStateEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyManagement::ESAStateEnum value); -} // namespace ESAState - -namespace AbsMinPower { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // power_mw -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace AbsMinPower - -namespace AbsMaxPower { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // power_mw -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace AbsMaxPower - -namespace FeatureMap { -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -} // namespace FeatureMap - namespace ClusterRevision { EmberAfStatus Get(chip::EndpointId endpoint, uint16_t * value); // int16u EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); @@ -2063,68 +2033,6 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); namespace EnergyEvse { namespace Attributes { -namespace State { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // StateEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::StateEnum value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, - const chip::app::DataModel::Nullable & value); -} // namespace State - -namespace SupplyState { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::SupplyStateEnum * value); // SupplyStateEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::SupplyStateEnum value); -} // namespace SupplyState - -namespace FaultState { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::FaultStateEnum * value); // FaultStateEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::EnergyEvse::FaultStateEnum value); -} // namespace FaultState - -namespace ChargingEnabledUntil { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace ChargingEnabledUntil - -namespace DischargingEnabledUntil { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace DischargingEnabledUntil - -namespace CircuitCapacity { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // amperage_ma -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace CircuitCapacity - -namespace MinimumChargeCurrent { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // amperage_ma -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace MinimumChargeCurrent - -namespace MaximumChargeCurrent { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // amperage_ma -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace MaximumChargeCurrent - -namespace MaximumDischargeCurrent { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // amperage_ma -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace MaximumDischargeCurrent - -namespace UserMaximumChargeCurrent { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // amperage_ma -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -} // namespace UserMaximumChargeCurrent - -namespace RandomizationDelayWindow { -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value); // elapsed_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -} // namespace RandomizationDelayWindow - namespace NumberOfWeeklyTargets { EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // int8u EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); @@ -2135,95 +2043,6 @@ EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // int8u EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); } // namespace NumberOfDailyTargets -namespace NextChargeStartTime { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace NextChargeStartTime - -namespace NextChargeTargetTime { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace NextChargeTargetTime - -namespace NextChargeRequiredEnergy { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // energy_mwh -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace NextChargeRequiredEnergy - -namespace NextChargeTargetSoC { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // percent -EmberAfStatus Set(chip::EndpointId endpoint, chip::Percent value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace NextChargeTargetSoC - -namespace ApproximateEVEfficiency { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // int16u -EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace ApproximateEVEfficiency - -namespace StateOfCharge { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // percent -EmberAfStatus Set(chip::EndpointId endpoint, chip::Percent value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace StateOfCharge - -namespace BatteryCapacity { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // energy_mwh -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace BatteryCapacity - -namespace VehicleID { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // char_string -EmberAfStatus Set(chip::EndpointId endpoint, chip::CharSpan value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace VehicleID - -namespace SessionID { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // int32u -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace SessionID - -namespace SessionDuration { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // elapsed_s -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace SessionDuration - -namespace SessionEnergyCharged { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // energy_mwh -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace SessionEnergyCharged - -namespace SessionEnergyDischarged { -EmberAfStatus Get(chip::EndpointId endpoint, DataModel::Nullable & value); // energy_mwh -EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); -EmberAfStatus SetNull(chip::EndpointId endpoint); -EmberAfStatus Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -} // namespace SessionEnergyDischarged - -namespace FeatureMap { -EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 -EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); -} // namespace FeatureMap - namespace ClusterRevision { EmberAfStatus Get(chip::EndpointId endpoint, uint16_t * value); // int16u EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value);