diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 9dfd4ffc50b6c9..66448c121f22db 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -22,6 +22,7 @@ set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/device-energy-management/include" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/energy-evse/include" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/energy-reporting/include" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/water-heater/include" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32" @@ -36,6 +37,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/device-energy-management/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/energy-evse/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/energy-reporting/src" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/water-heater/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/ota" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common" diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index baac52014d3c3b..5c61b4db461942 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -29,10 +29,6 @@ if (chip_enable_pw_rpc) { source_set("chip-all-clusters-common") { sources = [ - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/WhmDelegateImpl.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/WhmInstance.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/WhmMain.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/WhmManufacturer.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/air-quality-instance.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/boolcfg-stub.cpp", @@ -62,7 +58,6 @@ 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/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp", "${chip_root}/examples/all-clusters-app/linux/diagnostic-logs-provider-delegate-impl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/common/src/EnergyTimeUtils.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp", @@ -75,6 +70,11 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseTargetsStore.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-evse/src/energy-evse-mode.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/ElectricalPowerMeasurementDelegate.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmInstance.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp", "${chip_root}/examples/thermostat/thermostat-common/src/thermostat-delegate-impl.cpp", "AllClustersCommandDelegate.cpp", "AllClustersCommandDelegate.h", @@ -102,6 +102,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/include", "${chip_root}/examples/energy-management-app/energy-management-common/energy-evse/include", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/include", + "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/include", "${chip_root}/examples/thermostat/thermostat-common/include", ] diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index badda7f3b68b40..42df91b845a610 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -285,7 +285,6 @@ void ApplicationShutdown() Clusters::WaterHeaterMode::Shutdown(); Clusters::WaterHeaterManagement::WhmApplicationShutdown(); - Clusters::WaterHeaterMode::Shutdown(); if (sChipNamedPipeCommands.Stop() != CHIP_NO_ERROR) { diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h b/examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h new file mode 100644 index 00000000000000..ac5cc5000e71b9 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h @@ -0,0 +1,23 @@ +/* + * + * Copyright (c) 2024 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 + +chip::app::Clusters::DeviceEnergyManagement::DeviceEnergyManagementDelegate * GetDEMDelegate(); diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp b/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp index 469b781a9b6211..ff545ecf38c762 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp +++ b/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp @@ -16,6 +16,7 @@ * limitations under the License. */ +#include #include #include #include @@ -41,16 +42,6 @@ static chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustCapabili static chip::app::DataModel::Nullable sPowerAdjustmentCapability; -DeviceEnergyManagementDelegate * GetDEMDelegate() -{ - EVSEManufacturer * mn = GetEvseManufacturer(); - VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); - DeviceEnergyManagementDelegate * dg = mn->GetDEMDelegate(); - VerifyOrDieWithMsg(dg != nullptr, AppServer, "DEM Delegate is null"); - - return dg; -} - CHIP_ERROR ConfigureForecast(uint16_t numSlots) { uint32_t chipEpoch = 0; @@ -92,9 +83,9 @@ CHIP_ERROR ConfigureForecast(uint16_t numSlots) if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kPowerForecastReporting)) { - sSlots[0].nominalPower.SetValue(1500); - sSlots[0].minPower.SetValue(1000); - sSlots[0].maxPower.SetValue(2000); + sSlots[0].nominalPower.SetValue(2500000); + sSlots[0].minPower.SetValue(1200000); + sSlots[0].maxPower.SetValue(7600000); } sSlots[0].nominalEnergy.SetValue(2000); @@ -119,9 +110,9 @@ CHIP_ERROR ConfigureForecast(uint16_t numSlots) if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kPowerForecastReporting)) { - sSlots[slotNo].nominalPower.SetValue(2 * sSlots[slotNo - 1].nominalPower.Value()); - sSlots[slotNo].minPower.SetValue(2 * sSlots[slotNo - 1].minPower.Value()); - sSlots[slotNo].maxPower.SetValue(2 * sSlots[slotNo - 1].maxPower.Value()); + sSlots[slotNo].nominalPower.SetValue(sSlots[slotNo - 1].nominalPower.Value()); + sSlots[slotNo].minPower.SetValue(sSlots[slotNo - 1].minPower.Value()); + sSlots[slotNo].maxPower.SetValue(sSlots[slotNo - 1].maxPower.Value()); sSlots[slotNo].nominalEnergy.SetValue(2 * sSlots[slotNo - 1].nominalEnergy.Value()); } @@ -134,10 +125,7 @@ CHIP_ERROR ConfigureForecast(uint16_t numSlots) sForecastStruct.slots = DataModel::List(sSlots, numSlots); - EVSEManufacturer * mn = GetEvseManufacturer(); - mn->GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); - mn->GetDEMDelegate()->SetAbsMinPower(1000); - mn->GetDEMDelegate()->SetAbsMaxPower(256 * 2000 * 1000); + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); return CHIP_NO_ERROR; } diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp index 273bc9e0614333..161ea2f77c0750 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp @@ -377,10 +377,14 @@ Status DeviceEnergyManagementDelegate::StartTimeAdjustRequest(const uint32_t req mForecast.Value().startTime = savedStartTime; mForecast.Value().endTime = savedEndTime; + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); + return Status::Failure; } } + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); + return Status::Success; } @@ -457,10 +461,14 @@ Status DeviceEnergyManagementDelegate::PauseRequest(const uint32_t durationS, Ad if (cause == AdjustmentCauseEnum::kLocalOptimization) { mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kLocalOptimization; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); } else if (cause == AdjustmentCauseEnum::kGridOptimization) { mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kGridOptimization; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); } return Status::Success; @@ -606,6 +614,8 @@ Status DeviceEnergyManagementDelegate::ResumeRequest() // The PauseRequest has effectively been cancelled so as a result the device should // go back to InternalOptimisation mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); } CHIP_ERROR err = CancelPauseRequestAndGenerateEvent(CauseEnum::kCancelled); @@ -672,6 +682,8 @@ Status DeviceEnergyManagementDelegate::ModifyForecastRequest( } mForecast.Value().forecastID++; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); } return status; @@ -725,6 +737,8 @@ Status DeviceEnergyManagementDelegate::RequestConstraintBasedForecast( mForecast.Value().forecastID++; + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); + status = Status::Success; } @@ -748,6 +762,8 @@ Status DeviceEnergyManagementDelegate::CancelRequest() mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); + /* It is expected the mpDEMManufacturerDelegate will cancel the effects of any previous adjustment * request commands, and re-evaluate its forecast for intended operation ignoring those previous * requests. @@ -980,6 +996,8 @@ CHIP_ERROR DeviceEnergyManagementDelegate::SetOptOutState(OptOutStateEnum newVal if ((mOptOutState == OptOutStateEnum::kOptOut) || (mOptOutState == OptOutStateEnum::kLocalOptOut)) { mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); // Generate a new forecast with Internal Optimization // TODO } @@ -988,6 +1006,8 @@ CHIP_ERROR DeviceEnergyManagementDelegate::SetOptOutState(OptOutStateEnum newVal if ((mOptOutState == OptOutStateEnum::kOptOut) || (mOptOutState == OptOutStateEnum::kGridOptOut)) { mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); // Generate a new forecast with Internal Optimization // TODO } diff --git a/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h b/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h index 2e7e29537ef3b4..07dce510e9b38c 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h +++ b/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h @@ -18,5 +18,16 @@ #pragma once +#include + void EvseApplicationInit(); void EvseApplicationShutdown(); + +CHIP_ERROR DeviceEnergyManagementInit(); +CHIP_ERROR DeviceEnergyManagementShutdown(); + +CHIP_ERROR EnergyMeterInit(); +CHIP_ERROR EnergyMeterShutdown(); + +CHIP_ERROR PowerTopologyInit(); +CHIP_ERROR PowerTopologyShutdown(); diff --git a/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp index 00ced85a9aa2b6..359e7c8066551d 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp +++ b/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp @@ -70,6 +70,10 @@ CHIP_ERROR EVSEManufacturer::Init() /* For Device Energy Management we need the ESA to be Online and ready to accept commands */ dem->SetESAState(ESAStateEnum::kOnline); + // Set the abs min and max power + dem->SetAbsMinPower(1200000); // 1.2KW + dem->SetAbsMaxPower(7600000); // 7.6KW + /* * This is an example implementation for manufacturers to consider * diff --git a/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp b/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp index bd22c67eafd9b5..8e900c0948008a 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp +++ b/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp @@ -67,6 +67,13 @@ EVSEManufacturer * EnergyEvse::GetEvseManufacturer() return gEvseManufacturer.get(); } +DeviceEnergyManagement::DeviceEnergyManagementDelegate * GetDEMDelegate() +{ + VerifyOrDieWithMsg(gDEMDelegate.get() != nullptr, AppServer, "DEM Delegate is null"); + + return gDEMDelegate.get(); +} + /* * @brief Creates a Delegate and Instance for DEM * @@ -472,7 +479,7 @@ void EvseApplicationInit() void EvseApplicationShutdown() { - ChipLogDetail(AppServer, "Energy Management App: ApplicationShutdown()"); + ChipLogDetail(AppServer, "Energy Management App (EVSE): ApplicationShutdown()"); /* Shutdown in reverse order that they were created */ EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */ 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 e7fba7e08e028f..faf05b7c182995 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 @@ -1737,6 +1737,67 @@ cluster ElectricalEnergyMeasurement = 145 { readonly attribute int16u clusterRevision = 65533; } +/** This cluster is used to allow clients to control the operation of a hot water heating appliance so that it can be used with energy management. */ +provisional cluster WaterHeaterManagement = 148 { + revision 2; + + enum BoostStateEnum : enum8 { + kInactive = 0; + kActive = 1; + } + + bitmap Feature : bitmap32 { + kEnergyManagement = 0x1; + kTankPercent = 0x2; + } + + bitmap WaterHeaterHeatSourceBitmap : bitmap8 { + kImmersionElement1 = 0x1; + kImmersionElement2 = 0x2; + kHeatPump = 0x4; + kBoiler = 0x8; + kOther = 0x10; + } + + struct WaterHeaterBoostInfoStruct { + elapsed_s duration = 0; + optional boolean oneShot = 1; + optional boolean emergencyBoost = 2; + optional temperature temporarySetpoint = 3; + optional percent targetPercentage = 4; + optional percent targetReheat = 5; + } + + info event BoostStarted = 0 { + WaterHeaterBoostInfoStruct boostInfo = 0; + } + + info event BoostEnded = 1 { + } + + readonly attribute WaterHeaterHeatSourceBitmap heaterTypes = 0; + readonly attribute WaterHeaterHeatSourceBitmap heatDemand = 1; + readonly attribute optional int16u tankVolume = 2; + readonly attribute optional energy_mwh estimatedHeatRequired = 3; + readonly attribute optional percent tankPercentage = 4; + readonly attribute BoostStateEnum boostState = 5; + 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 BoostRequest { + WaterHeaterBoostInfoStruct boostInfo = 0; + } + + /** Allows a client to request that the water heater is put into a Boost state. */ + command access(invoke: manage) Boost(BoostRequest): DefaultSuccess = 0; + /** Allows a client to cancel an ongoing Boost operation. */ + command access(invoke: manage) CancelBoost(): DefaultSuccess = 1; +} + /** 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 4; @@ -2210,6 +2271,56 @@ cluster EnergyEvseMode = 157 { command ChangeToMode(ChangeToModeRequest): ChangeToModeResponse = 0; } +/** Attributes and commands for selecting a mode from a list of supported options. */ +cluster WaterHeaterMode = 158 { + revision 1; + + enum ModeTag : enum16 { + kOff = 16384; + kManual = 16385; + kTimed = 16386; + } + + bitmap Feature : bitmap32 { + kOnOff = 0x1; + } + + struct ModeTagStruct { + optional vendor_id mfgCode = 0; + enum16 value = 1; + } + + struct ModeOptionStruct { + char_string<64> label = 0; + int8u mode = 1; + ModeTagStruct modeTags[] = 2; + } + + readonly attribute ModeOptionStruct supportedModes[] = 0; + readonly attribute int8u currentMode = 1; + attribute optional nullable int8u startUpMode = 2; + attribute optional nullable int8u onMode = 3; + 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 ChangeToModeRequest { + int8u newMode = 0; + } + + response struct ChangeToModeResponse = 1 { + enum8 status = 0; + optional char_string statusText = 1; + } + + /** This command is used to change device modes. + On receipt of this command the device SHALL respond with a ChangeToModeResponse command. */ + command ChangeToMode(ChangeToModeRequest): ChangeToModeResponse = 0; +} + /** Attributes and commands for selecting a mode from a list of supported options. */ provisional cluster DeviceEnergyManagementMode = 159 { revision 1; @@ -2557,6 +2668,24 @@ endpoint 1 { ram attribute clusterRevision default = 1; } + server cluster WaterHeaterManagement { + callback attribute heaterTypes; + callback attribute heatDemand; + callback attribute tankVolume; + callback attribute estimatedHeatRequired; + callback attribute tankPercentage; + callback attribute boostState; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command Boost; + handle command CancelBoost; + } + server cluster DeviceEnergyManagement { emits event PowerAdjustStart; emits event PowerAdjustEnd; @@ -2640,8 +2769,20 @@ endpoint 1 { server cluster EnergyEvseMode { callback attribute supportedModes; callback attribute currentMode; - ram attribute startUpMode; - ram attribute onMode; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + + handle command ChangeToMode; + handle command ChangeToModeResponse; + } + + server cluster WaterHeaterMode { + callback attribute supportedModes; + callback attribute currentMode; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2656,8 +2797,6 @@ endpoint 1 { server cluster DeviceEnergyManagementMode { callback attribute supportedModes; callback attribute currentMode; - ram attribute startUpMode; - ram attribute onMode; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; 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 566588ab8e4d0d..1a312c93abed59 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 @@ -3696,6 +3696,227 @@ } ] }, + { + "name": "Water Heater Management", + "code": 148, + "mfgCode": null, + "define": "WATER_HEATER_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "Boost", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CancelBoost", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "HeaterTypes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "WaterHeaterHeatSourceBitmap", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HeatDemand", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "WaterHeaterHeatSourceBitmap", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TankVolume", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EstimatedHeatRequired", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TankPercentage", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "percent", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BoostState", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "BoostStateEnum", + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Device Energy Management", "code": 152, @@ -4680,32 +4901,156 @@ "reportableChange": 0 }, { - "name": "StartUpMode", - "code": 2, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", - "type": "int8u", + "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": null, + "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": "", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 + } + ] + }, + { + "name": "Water Heater Mode", + "code": 158, + "mfgCode": null, + "define": "WATER_HEATER_MODE_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "OnMode", - "code": 3, + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedModes", + "code": 0, + "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": "CurrentMode", + "code": 1, "mfgCode": null, "side": "server", "type": "int8u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -4868,38 +5213,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "StartUpMode", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "OnMode", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "GeneratedCommandList", "code": 65528, diff --git a/examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h b/examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h new file mode 100644 index 00000000000000..819ff9e4d160ca --- /dev/null +++ b/examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2024 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 + +namespace chip { +namespace app { +namespace Clusters { +namespace WaterHeaterManagement { + +void FullWhmApplicationInit(); +void FullWhmApplicationShutdown(); + +} // namespace WaterHeaterManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/include/WhmDelegate.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h similarity index 100% rename from examples/all-clusters-app/all-clusters-common/include/WhmDelegate.h rename to examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h diff --git a/examples/all-clusters-app/all-clusters-common/include/WhmInstance.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmInstance.h similarity index 100% rename from examples/all-clusters-app/all-clusters-common/include/WhmInstance.h rename to examples/energy-management-app/energy-management-common/water-heater/include/WhmInstance.h diff --git a/examples/all-clusters-app/all-clusters-common/include/WhmMain.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h similarity index 89% rename from examples/all-clusters-app/all-clusters-common/include/WhmMain.h rename to examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h index 21dc9d86519307..34f04d8cbb6b8f 100644 --- a/examples/all-clusters-app/all-clusters-common/include/WhmMain.h +++ b/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h @@ -18,13 +18,15 @@ #pragma once +#include + namespace chip { namespace app { namespace Clusters { namespace WaterHeaterManagement { -void WhmApplicationInit(); -void WhmApplicationShutdown(); +CHIP_ERROR WhmApplicationInit(); +CHIP_ERROR WhmApplicationShutdown(); } // namespace WaterHeaterManagement } // namespace Clusters diff --git a/examples/all-clusters-app/all-clusters-common/include/WhmManufacturer.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmManufacturer.h similarity index 94% rename from examples/all-clusters-app/all-clusters-common/include/WhmManufacturer.h rename to examples/energy-management-app/energy-management-common/water-heater/include/WhmManufacturer.h index b56aa24abf491f..3a48b467ee22c5 100644 --- a/examples/all-clusters-app/all-clusters-common/include/WhmManufacturer.h +++ b/examples/energy-management-app/energy-management-common/water-heater/include/WhmManufacturer.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include @@ -32,7 +33,7 @@ namespace WaterHeaterManagement { * Helps with handling the test triggers. */ -class WhmManufacturer +class WhmManufacturer : public DeviceEnergyManagement::DEMManufacturerDelegate { public: WhmManufacturer(WaterHeaterManagementInstance * whmInstance) { mWhmInstance = whmInstance; } @@ -139,6 +140,13 @@ class WhmManufacturer */ void BoostCommandFinished(); + /* Implement the DEMManufacturerDelegate interface */ + + /** + * @brief The PowerAdjustEnd event needs to report the approximate energy used by the ESA during the session. + */ + int64_t GetApproxEnergyDuringSession() override; + private: WaterHeaterManagementInstance * mWhmInstance; }; diff --git a/examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h b/examples/energy-management-app/energy-management-common/water-heater/include/water-heater-mode.h similarity index 100% rename from examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h rename to examples/energy-management-app/energy-management-common/water-heater/include/water-heater-mode.h diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp new file mode 100644 index 00000000000000..0dcfb81f59a8f0 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 2024 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 "EnergyManagementAppCmdLineOptions.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace WaterHeaterManagement { + +void FullWhmApplicationInit() +{ + ReturnOnFailure(WhmApplicationInit()); + + if (DeviceEnergyManagementInit() != CHIP_NO_ERROR) + { + WhmApplicationShutdown(); + return; + } + + if (EnergyMeterInit() != CHIP_NO_ERROR) + { + DeviceEnergyManagementShutdown(); + WhmApplicationShutdown(); + return; + } + + if (PowerTopologyInit() != CHIP_NO_ERROR) + { + EnergyMeterShutdown(); + DeviceEnergyManagementShutdown(); + WhmApplicationShutdown(); + return; + } + + /* For Device Energy Management we need the ESA to be Online and ready to accept commands */ + + GetDEMDelegate()->SetESAState(ESAStateEnum::kOnline); + GetDEMDelegate()->SetDEMManufacturerDelegate(*GetWhmManufacturer()); + + // Set the abs min and max power + GetDEMDelegate()->SetAbsMinPower(1200000); // 1.2KW + GetDEMDelegate()->SetAbsMaxPower(7600000); // 7.6KW +} + +void FullWhmApplicationShutdown() +{ + ChipLogDetail(AppServer, "Energy Management App (WaterHeater): ApplicationShutdown()"); + + /* Shutdown in reverse order that they were created */ + PowerTopologyShutdown(); /* Free the PowerTopology */ + EnergyMeterShutdown(); /* Free the Energy Meter */ + DeviceEnergyManagementShutdown(); /* Free the DEM */ + WhmApplicationShutdown(); + + Clusters::DeviceEnergyManagementMode::Shutdown(); + Clusters::WaterHeaterMode::Shutdown(); +} + +} // namespace WaterHeaterManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/src/WhmDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp similarity index 100% rename from examples/all-clusters-app/all-clusters-common/src/WhmDelegateImpl.cpp rename to examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp diff --git a/examples/all-clusters-app/all-clusters-common/src/WhmInstance.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmInstance.cpp similarity index 100% rename from examples/all-clusters-app/all-clusters-common/src/WhmInstance.cpp rename to examples/energy-management-app/energy-management-common/water-heater/src/WhmInstance.cpp diff --git a/examples/all-clusters-app/all-clusters-common/src/WhmMain.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp similarity index 95% rename from examples/all-clusters-app/all-clusters-common/src/WhmMain.cpp rename to examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp index ea59fef2d095f5..038e332bd31aff 100644 --- a/examples/all-clusters-app/all-clusters-common/src/WhmMain.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp @@ -167,25 +167,22 @@ CHIP_ERROR WhmManufacturerShutdown() return CHIP_NO_ERROR; } -void WhmApplicationInit() +CHIP_ERROR WhmApplicationInit() { - if (WhmInit() != CHIP_NO_ERROR) - { - return; - } + ReturnErrorOnFailure(WhmInit()); /* Do this last so that the instances for other clusters can be wrapped inside */ - if (WhmManufacturerInit() != CHIP_NO_ERROR) - { - WhmShutdown(); - return; - } + ReturnErrorOnFailure(WhmManufacturerInit()); + + return CHIP_NO_ERROR; } -void WhmApplicationShutdown() +CHIP_ERROR WhmApplicationShutdown() { /* Shutdown in reverse order that they were created */ WhmManufacturerShutdown(); + + return WhmShutdown(); } } // namespace WaterHeaterManagement diff --git a/examples/all-clusters-app/all-clusters-common/src/WhmManufacturer.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp similarity index 98% rename from examples/all-clusters-app/all-clusters-common/src/WhmManufacturer.cpp rename to examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp index 8865501fcca6fe..af01f36bc5da69 100644 --- a/examples/all-clusters-app/all-clusters-common/src/WhmManufacturer.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp @@ -160,6 +160,12 @@ WaterHeaterManagementDelegate * GetWhmDelegate() return wg; } +// The PowerAdjustEnd event needs to report the approximate energy used by the ESA during the session. +int64_t WhmManufacturer::GetApproxEnergyDuringSession() +{ + return 300; +} + void SetTestEventTrigger_BasicInstallationTestEvent() { WaterHeaterManagementDelegate * dg = GetWhmDelegate(); diff --git a/examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp similarity index 100% rename from examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp rename to examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp diff --git a/examples/energy-management-app/esp32/README.md b/examples/energy-management-app/esp32/README.md index c2fb2bc7a1f63c..8e0d127f21b56d 100644 --- a/examples/energy-management-app/esp32/README.md +++ b/examples/energy-management-app/esp32/README.md @@ -1,7 +1,8 @@ # Matter ESP32 Energy Management Example -This example demonstrates the Matter Electric Vehicle Supply Equipment -application on ESP platforms. +This example demonstrates the Matter Electric Vehicle Supply Equipment and Water +Heater example application along with several other energy management clusters +on ESP platforms. Please [setup ESP-IDF and CHIP Environment](../../../docs/guides/esp32/setup_idf_chip.md) @@ -35,6 +36,41 @@ cp /path/to/auth/key.txt path/to/connectedhomeip/examples/energy-management-app/ --- +### Build time configuration + +- Application mode: By default the example app will run the EVSE example, + however this can be changed using the `idy.py menuconfig` command and + searching for: + + ENABLE_EXAMPLE_WATER_HEATER_DEVICE + ENABLE_EXAMPLE_EVSE_DEVICE + +- Test Event Trigger support: By default the EVSE, Water Heater, Device Energy + Management (DEM), Energy Reporting test event triggers are enabled in the + build. To turn these off run `idf.py menuconfig` and search for the + following config entries: + + ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER + ENABLE_ENERGY_EVSE_TRIGGER + ENABLE_WATER_HEATER_MANAGEMENT_TRIGGER + ENABLE_ENERGY_REPORTING_TRIGGER + +- Device Energy Management feature support: Depending on the capabilities of + the device it may support Power Forecast Reporting `PFR` or State Forecast + Reporting `SFR`. However it is not allowed to support both of these at once. + + By default `PFR` is enabled in the build. To change this run + `idf.py menuconfig` and search for the following config entries: + + DEM_SUPPORT_STATE_FORECAST_REPORTING + DEM_SUPPORT_POWER_FORECAST_REPORTING + + Note only one of these can be enabled to meet Matter specification + conformance. + + When running in test events, some test cases (e.g. TC_DEM_2.7 and + TC_DEM_2.8) depend on the correct setting to be used in the binary DUT. + ### Cluster Control - After successful commissioning, use the Energy Electric Vehicle Supply @@ -47,3 +83,6 @@ cp /path/to/auth/key.txt path/to/connectedhomeip/examples/energy-management-app/ ``` $ ./out/debug/chip-tool energyevse enable-charging 0xFFFFFFFF 6000 32000 1 --timedInteractionTimeoutMs