diff --git a/examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h index 27d8cd7cd96ecf..dffa91b5297efc 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h +++ b/examples/energy-management-app/energy-management-common/water-heater/include/WhmDelegate.h @@ -104,8 +104,8 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate * SHALL be rejected with appropriate error. */ Protocols::InteractionModel::Status HandleBoost(uint32_t duration, Optional oneShot, Optional emergencyBoost, - Optional temporarySetpoint, Optional targetPercentage, - Optional targetReheat) override; + Optional temporarySetpoint, Optional targetPercentage, + Optional targetReheat) override; /** * @brief Delegate should implement a handler to cancel a boost command. @@ -121,7 +121,7 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate BitMask GetHeaterTypes() override; BitMask GetHeatDemand() override; uint16_t GetTankVolume() override; - int64_t GetEstimatedHeatRequired() override; + Energy_mWh GetEstimatedHeatRequired() override; Percent GetTankPercentage() override; BoostStateEnum GetBoostState() override; @@ -130,7 +130,7 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate void SetHeaterTypes(BitMask heaterTypes); void SetHeatDemand(BitMask heatDemand); void SetTankVolume(uint16_t tankVolume); - void SetEstimatedHeatRequired(int64_t estimatedHeatRequired); + void SetEstimatedHeatRequired(Energy_mWh estimatedHeatRequired); void SetTankPercentage(Percent tankPercentage); void SetBoostState(BoostStateEnum boostState); @@ -152,19 +152,22 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate * * @param waterTemperature The water temperature in 100th's Celsius */ - void SetWaterTemperature(uint16_t waterTemperature); + void SetWaterTemperature(int16_t waterTemperature); /** * @brief Set the target water temperature of the tank * * @param targetWaterTemperature The water temperature in 100th's Celsius */ - void SetTargetWaterTemperature(uint16_t targetWaterTemperature); + void SetTargetWaterTemperature(int16_t targetWaterTemperature); /** - * @brief Determine whether the heating sources need to be turned on or off + * @brief Determine whether the heating sources need to be turned on or off or left unchanged. + * + * @return Success if the heating was successfully turned on or off or left unchanged otherwise an error + * code is returned if turning the heating on or off failed. */ - Protocols::InteractionModel::Status CheckIfHeatNeedsToBeTurnedOnOrOff(); + Protocols::InteractionModel::Status ChangeHeatingIfNecessary(); /** * @brief Static timer callback for when Boost timer expires. @@ -194,9 +197,34 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate * @param replacedWaterTemperature The temperature of the * percentageReplaced water. */ - void DrawOffHotWater(chip::Percent percentageReplaced, uint16_t replacedWaterTemperature); + void DrawOffHotWater(Percent percentageReplaced, int16_t replacedWaterTemperature); + + /** + * Set the temperature of the cold water that fills the tank as the hot water + * is drawn off. + * + * @param coldWaterTemperature The cold water temperature in 100th of a C + */ + void SetColdWaterTemperature(int16_t coldWaterTemperature); private: + /** + * Return the target temperature. + * If a boost command is in progress and has a mBoostTemporarySetpoint value use that as the + * target temperature otherwise use the temperature set via SetTargetWaterTemperature(). + * + * @return the target temperature + */ + int16_t GetActiveTargetWaterTemperature() const; + + /** + * @brief Calculate the percentage of the water in the tank at the target + * temperature. + * + * @return Percentage of water at the target temperature + */ + uint8_t CalculateTankPercentage() const; + /** * @brief Determine whether heating needs to be turned on or off or left as * is. @@ -223,13 +251,13 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate WhmManufacturer * mpWhmManufacturer; // Target water temperature in 100ths of a C - uint16_t mTargetWaterTemperature; + int16_t mTargetWaterTemperature; // Actual water temperature in 100ths of a C - uint16_t mWaterTemperature; + int16_t mWaterTemperature; - // The % of water at temperature mReplacedWaterTemperature - uint16_t mReplacedWaterTemperature; + // The cold water temperature in 100ths of a C + int16_t mColdWaterTemperature; // Boost command parameters @@ -253,7 +281,7 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate // amount of water that SHALL be heated by this Boost command before the // heater is switched off. This field is optional, however it SHALL be // included if the TargetReheat field is included. - Optional mBoostTargetPercentage; + Optional mBoostTargetPercentage; // If the tank supports the TankPercent feature, and the heating by this // Boost command has ceased because the TargetPercentage of the water in the @@ -266,7 +294,7 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate // heat back up to 80% of hot water. If this field and the OneShot field // were both omitted, heating would begin again after any water draw which // reduced the TankPercentage below 80%. - Optional mBoostTargetReheat; + Optional mBoostTargetReheat; // Track whether the water temperature has reached the water temperature // specified in the boost command. Used in conjunction with the boost @@ -299,7 +327,7 @@ class WaterHeaterManagementDelegate : public WaterHeaterManagement::Delegate // taking the specific heat capacity of water (4182 J/kg °C) and by knowing // the current temperature of the water, the tank volume and target // temperature. - int64_t mEstimatedHeatRequired; + Energy_mWh mEstimatedHeatRequired; // This attribute SHALL indicate an approximate level of hot water stored in // the tank, which may help consumers understand the amount of hot water diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp index af09a13a0dab2d..79a64d5226f486 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp @@ -21,6 +21,8 @@ #include #include +#include + using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; @@ -29,7 +31,7 @@ using namespace chip::app::Clusters::WaterHeaterManagement; using Protocols::InteractionModel::Status; WaterHeaterManagementDelegate::WaterHeaterManagementDelegate(EndpointId clustersEndpoint) : - mpWhmInstance(nullptr), mpWhmManufacturer(nullptr), mWaterTemperature(0), mReplacedWaterTemperature(0), + mpWhmInstance(nullptr), mpWhmManufacturer(nullptr), mTargetWaterTemperature(0), mWaterTemperature(0), mColdWaterTemperature(0), mBoostTargetTemperatureReached(false), mTankVolume(0), mEstimatedHeatRequired(0), mTankPercentage(0), mBoostState(BoostStateEnum::kInactive) {} @@ -65,7 +67,7 @@ uint16_t WaterHeaterManagementDelegate::GetTankVolume() return mTankVolume; } -int64_t WaterHeaterManagementDelegate::GetEstimatedHeatRequired() +Energy_mWh WaterHeaterManagementDelegate::GetEstimatedHeatRequired() { return mEstimatedHeatRequired; } @@ -110,7 +112,7 @@ void WaterHeaterManagementDelegate::SetTankVolume(uint16_t tankVolume) } } -void WaterHeaterManagementDelegate::SetEstimatedHeatRequired(int64_t estimatedHeatRequired) +void WaterHeaterManagementDelegate::SetEstimatedHeatRequired(Energy_mWh estimatedHeatRequired) { if (mEstimatedHeatRequired != estimatedHeatRequired) { @@ -128,8 +130,6 @@ void WaterHeaterManagementDelegate::SetTankPercentage(Percent tankPercentage) { mTankPercentage = tankPercentage; - CheckIfHeatNeedsToBeTurnedOnOrOff(); - MatterReportingAttributeChangeCallback(mEndpointId, WaterHeaterManagement::Id, Attributes::TankPercentage::Id); } } @@ -201,13 +201,22 @@ Status WaterHeaterManagementDelegate::HandleBoost(uint32_t durationS, OptionalBoostCommandCancelled(); VerifyOrReturnValue(status == Status::Success, status); - status = CheckIfHeatNeedsToBeTurnedOnOrOff(); + // Note ChangeHeatingIfNecessary can generate a BoostEnded event but only if the boost state is kActive + // which it cannot be when called from here. + status = ChangeHeatingIfNecessary(); VerifyOrReturnValue(status == Status::Success, status); + + CHIP_ERROR err = GenerateBoostEndedEvent(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "HandleCancelBoost: Failed to generate BoostEnded event: %" CHIP_ERROR_FORMAT, err.Format()); + + return Status::Failure; + } } return Status::Success; @@ -273,61 +300,83 @@ Status WaterHeaterManagementDelegate::HandleCancelBoost() * *********************************************************************************/ -void WaterHeaterManagementDelegate::SetWaterTemperature(uint16_t waterTemperature) +int16_t WaterHeaterManagementDelegate::GetActiveTargetWaterTemperature() const +{ + // Determine the target temperature. If a boost command is in progress and has a mBoostTemporarySetpoint value use that as the + // target temperature. + // Note, in practise the actual heating is likely to be controlled by the thermostat's occupiedHeatingSetpoint most of the + // time, and the TemporarySetpoint (if not null) would be overiding the thermostat's occupiedHeatingSetpoint. + // However, this code doesn't rely upon the thermostat cluster. + int16_t targetTemperature = (mBoostState == BoostStateEnum::kActive && mBoostTemporarySetpoint.HasValue()) + ? mBoostTemporarySetpoint.Value() + : mTargetWaterTemperature; + + return targetTemperature; +} + +uint8_t WaterHeaterManagementDelegate::CalculateTankPercentage() const +{ + int32_t tankPercentage; + int32_t divisor = static_cast(GetActiveTargetWaterTemperature()) - static_cast(mColdWaterTemperature); + + tankPercentage = 100; + if (divisor > 0) + { + tankPercentage = 100 * (static_cast(mWaterTemperature) - static_cast(mColdWaterTemperature)) / divisor; + } + + tankPercentage = std::min(tankPercentage, static_cast(100)); + tankPercentage = std::max(tankPercentage, static_cast(0)); + + return static_cast(tankPercentage); +} + +void WaterHeaterManagementDelegate::SetColdWaterTemperature(int16_t coldWaterTemperature) +{ + mColdWaterTemperature = coldWaterTemperature; +} + +void WaterHeaterManagementDelegate::SetWaterTemperature(int16_t waterTemperature) { mWaterTemperature = waterTemperature; if (mpWhmInstance != nullptr && mpWhmInstance->HasFeature(Feature::kTankPercent)) { - mTankPercentage = 100; + // Recalculate the tankPercentage as the waterTemperature has changed + SetTankPercentage(CalculateTankPercentage()); } // See if the heat needs to be turned on or off - CheckIfHeatNeedsToBeTurnedOnOrOff(); + ChangeHeatingIfNecessary(); } -void WaterHeaterManagementDelegate::SetTargetWaterTemperature(uint16_t targetWaterTemperature) +void WaterHeaterManagementDelegate::SetTargetWaterTemperature(int16_t targetWaterTemperature) { mTargetWaterTemperature = targetWaterTemperature; // See if the heat needs to be turned on or off - CheckIfHeatNeedsToBeTurnedOnOrOff(); + ChangeHeatingIfNecessary(); } -void WaterHeaterManagementDelegate::DrawOffHotWater(Percent percentageReplaced, uint16_t replacedWaterTemperature) +void WaterHeaterManagementDelegate::DrawOffHotWater(Percent percentageReplaced, int16_t replacedWaterTemperature) { - // Only supported in the kTankPercent is supported. + // First calculate the new average water temperature + mWaterTemperature = static_cast( + (mWaterTemperature * (100 - percentageReplaced) + replacedWaterTemperature * percentageReplaced) / 100); + // Replaces percentageReplaced% of the water in the tank with water of a temperature replacedWaterTemperature + // Only supported if the kTankPercent feature is supported. if (mpWhmInstance != nullptr && mpWhmInstance->HasFeature(Feature::kTankPercent)) { - // See if all of the water has now been replaced with replacedWaterTemperature - if (mTankPercentage >= percentageReplaced) - { - mTankPercentage = static_cast(mTankPercentage - percentageReplaced); - } - else - { - mTankPercentage = 0; - } - - mReplacedWaterTemperature = replacedWaterTemperature; + SetTankPercentage(CalculateTankPercentage()); - CheckIfHeatNeedsToBeTurnedOnOrOff(); + ChangeHeatingIfNecessary(); } } bool WaterHeaterManagementDelegate::HasWaterTemperatureReachedTarget() const { - // Determine the target temperature. If a boost command is in progress and has a mBoostTemporarySetpoint value use that as the - // target temperature. - // Note, in practise the actual heating is likely to be controlled by the thermostat's occupiedHeatingSetpoint most of the - // time, and the TemporarySetpoint (if not null) would be overiding the thermostat's occupiedHeatingSetpoint. - // However, this code doesn't rely upon the thermostat cluster. - uint16_t targetTemperature = (mBoostState == BoostStateEnum::kActive && mBoostTemporarySetpoint.HasValue()) - ? static_cast(mBoostTemporarySetpoint.Value()) - : mTargetWaterTemperature; - - VerifyOrReturnValue(mWaterTemperature >= targetTemperature, false); + int16_t targetTemperature = GetActiveTargetWaterTemperature(); if (mBoostState == BoostStateEnum::kActive) { @@ -351,13 +400,22 @@ bool WaterHeaterManagementDelegate::HasWaterTemperatureReachedTarget() const // If tank percentage is supported AND the targetPercentage.HasValue() then use target percentage to heat up. VerifyOrReturnValue(mTankPercentage >= mBoostTargetPercentage.Value(), false); } + else + { + VerifyOrReturnValue(mWaterTemperature >= targetTemperature, false); + } + } + else + { + // Just relying on mWaterTemperature to determine whether the temperature is at the target temperature + VerifyOrReturnValue(mWaterTemperature >= targetTemperature, false); } // Must have reached the right temperature return true; } -Status WaterHeaterManagementDelegate::CheckIfHeatNeedsToBeTurnedOnOrOff() +Status WaterHeaterManagementDelegate::ChangeHeatingIfNecessary() { VerifyOrReturnError(mpWhmManufacturer != nullptr, Status::InvalidInState); @@ -384,6 +442,13 @@ Status WaterHeaterManagementDelegate::CheckIfHeatNeedsToBeTurnedOnOrOff() mBoostEmergencyBoost.ClearValue(); status = mpWhmManufacturer->BoostCommandCancelled(); + + CHIP_ERROR err = GenerateBoostEndedEvent(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ChangeHeatingIfNecessary: Failed to generate BoostEnded event: %" CHIP_ERROR_FORMAT, + err.Format()); + } } // Turn the heating off @@ -457,5 +522,5 @@ Status WaterHeaterManagementDelegate::SetWaterHeaterMode(uint8_t modeValue) return status; } - return CheckIfHeatNeedsToBeTurnedOnOrOff(); + return ChangeHeatingIfNecessary(); } diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp index af01f36bc5da69..446d684e41be64 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmManufacturer.cpp @@ -44,8 +44,7 @@ CHIP_ERROR WhmManufacturer::Init() } dg->SetHeaterTypes(BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement1)); - dg->SetHeatDemand(BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement1)); - dg->SetEstimatedHeatRequired(10000); + dg->SetColdWaterTemperature(2000); return CHIP_NO_ERROR; } @@ -65,38 +64,30 @@ BitMask WhmManufacturer::DetermineHeatingSources() } // A list of valid heaterTypes - uint8_t waterHeaterTypeValues[] = { - static_cast(WaterHeaterHeatSourceBitmap::kImmersionElement1), - static_cast(WaterHeaterHeatSourceBitmap::kImmersionElement2), - static_cast(WaterHeaterHeatSourceBitmap::kHeatPump), - static_cast(WaterHeaterHeatSourceBitmap::kBoiler), - static_cast(WaterHeaterHeatSourceBitmap::kOther), - }; - - // The corresponding list of valid headerDemands - uint8_t waterHeaterDemandValues[] = { - static_cast(WaterHeaterHeatSourceBitmap::kImmersionElement1), - static_cast(WaterHeaterHeatSourceBitmap::kImmersionElement2), - static_cast(WaterHeaterHeatSourceBitmap::kHeatPump), - static_cast(WaterHeaterHeatSourceBitmap::kBoiler), - static_cast(WaterHeaterHeatSourceBitmap::kOther), + BitMask waterHeaterTypeValues[] = { + BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement1), + BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement2), + BitMask(WaterHeaterHeatSourceBitmap::kHeatPump), + BitMask(WaterHeaterHeatSourceBitmap::kBoiler), + BitMask(WaterHeaterHeatSourceBitmap::kOther), }; // Iterate across the valid waterHeaterTypes seeing which heating sources are available based on heaterTypes. // Set the corresponding bit in the heaterDemand bitmap. - BitMask heaterTypes = dg->GetHeaterTypes(); + BitMask waterHeaterTypes = dg->GetHeaterTypes(); + + BitMask waterHeaterDemand; - uint8_t heaterDemandMask = 0; - for (uint16_t idx = 0; idx < static_cast(sizeof(waterHeaterTypeValues) / sizeof(waterHeaterTypeValues[0])); idx++) + for (auto & waterHeaterType : waterHeaterTypeValues) { // Is this heating source being used? - if (heaterTypes.Raw() & waterHeaterTypeValues[idx]) + if (waterHeaterTypes.Has(waterHeaterType)) { - heaterDemandMask |= waterHeaterDemandValues[idx]; + waterHeaterDemand.Set(waterHeaterType); } } - return BitMask(heaterDemandMask); + return waterHeaterDemand; } Status WhmManufacturer::TurnHeatingOn(bool emergencyBoost) @@ -173,7 +164,11 @@ void SetTestEventTrigger_BasicInstallationTestEvent() // Simulate installation in a 100L tank full of water at 20C, with a target temperature of 60C, in OFF mode dg->SetTankVolume(100); dg->SetTargetWaterTemperature(6000); - dg->SetHeaterTypes(BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement1)); + + // kImmersionElement2 will be used in addition to kImmersionElement1 when emergencyBoost is specified + // in the BoostStarted command. + dg->SetHeaterTypes(BitMask(WaterHeaterHeatSourceBitmap::kImmersionElement1, + WaterHeaterHeatSourceBitmap::kImmersionElement2)); dg->DrawOffHotWater(100, 2000); } diff --git a/examples/energy-management-app/esp32/main/main.cpp b/examples/energy-management-app/esp32/main/main.cpp index 33623882cc2e7c..d235fa4291ac98 100644 --- a/examples/energy-management-app/esp32/main/main.cpp +++ b/examples/energy-management-app/esp32/main/main.cpp @@ -237,7 +237,15 @@ extern "C" void app_main() #endif ESP_LOGI(TAG, "=================================================="); - ESP_LOGI(TAG, "chip-esp32-energy-management-example starting"); +#if defined(CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE) + ESP_LOGI(TAG, "chip-esp32-energy-management-example evse starting. featureMap 0x%08lx", + DeviceEnergyManagement::sFeatureMap.Raw()); +#elif defined(CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE) + ESP_LOGI(TAG, "chip-esp32-energy-management-example water-heater starting. featureMap 0x%08lx", + DeviceEnergyManagement::sFeatureMap.Raw()); +#else + ESP_LOGI(TAG, "chip-esp32-energy-management-example starting. featureMap 0x%08lx", DeviceEnergyManagement::sFeatureMap.Raw()); +#endif ESP_LOGI(TAG, "=================================================="); #if CONFIG_ENABLE_CHIP_SHELL diff --git a/src/app/clusters/water-heater-management-server/water-heater-management-server.cpp b/src/app/clusters/water-heater-management-server/water-heater-management-server.cpp index 3cbe76f60d38f4..165fc94fb319a2 100644 --- a/src/app/clusters/water-heater-management-server/water-heater-management-server.cpp +++ b/src/app/clusters/water-heater-management-server/water-heater-management-server.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,59 @@ namespace app { namespace Clusters { namespace WaterHeaterManagement { -constexpr uint16_t kClusterRevision = 1; +constexpr uint16_t kClusterRevision = 2; + +/*************************************************************************** + * + * The Delegate implementation + * + ***************************************************************************/ + +CHIP_ERROR Delegate::GenerateBoostStartedEvent(uint32_t durationSecs, Optional oneShot, Optional emergencyBoost, + Optional temporarySetpoint, Optional targetPercentage, + Optional targetReheat) +{ + Events::BoostStarted::Type event; + EventNumber eventNumber; + + event.boostInfo.duration = durationSecs; + event.boostInfo.oneShot = oneShot; + event.boostInfo.emergencyBoost = emergencyBoost; + event.boostInfo.temporarySetpoint = temporarySetpoint; + event.boostInfo.targetPercentage = targetPercentage; + event.boostInfo.targetReheat = targetReheat; + + CHIP_ERROR err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Unable to generate BoostStarted event: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + return err; +} + +CHIP_ERROR Delegate::GenerateBoostEndedEvent() +{ + Events::BoostEnded::Type event; + EventNumber eventNumber; + ChipLogError(AppServer, "Delegate::GenerateBoostEndedEvent"); + + CHIP_ERROR err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Unable to generate BoostEnded event: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + return err; +} + +/*************************************************************************** + * + * The Instance implementation + * + ***************************************************************************/ CHIP_ERROR Instance::Init() { diff --git a/src/app/clusters/water-heater-management-server/water-heater-management-server.h b/src/app/clusters/water-heater-management-server/water-heater-management-server.h index 71a52de9b45eef..25ff16265b6df7 100644 --- a/src/app/clusters/water-heater-management-server/water-heater-management-server.h +++ b/src/app/clusters/water-heater-management-server/water-heater-management-server.h @@ -108,10 +108,30 @@ class Delegate virtual BitMask GetHeaterTypes() = 0; virtual BitMask GetHeatDemand() = 0; virtual uint16_t GetTankVolume() = 0; - virtual int64_t GetEstimatedHeatRequired() = 0; + virtual Energy_mWh GetEstimatedHeatRequired() = 0; virtual Percent GetTankPercentage() = 0; virtual BoostStateEnum GetBoostState() = 0; + // ------------------------------------------------------------------ + // Event generation + + /** + * @brief Generates a BoostStarted event. + * The parameters are same as those passed to HandleBoost(). + * + * @return CHIP_NO_ERROR if the event was successfully generated, otherwise an error. + */ + CHIP_ERROR GenerateBoostStartedEvent(uint32_t durationSecs, Optional oneShot, Optional emergencyBoost, + Optional temporarySetpoint, Optional targetPercentage, + Optional targetReheat); + + /** + * @brief Generates a BoostEnded event. + * + * @return CHIP_NO_ERROR if the event was successfully generated, otherwise an error. + */ + CHIP_ERROR GenerateBoostEndedEvent(); + protected: EndpointId mEndpointId = 0; }; diff --git a/src/app/util/basic-types.h b/src/app/util/basic-types.h index 97aebe690423c0..449756fe90ef42 100644 --- a/src/app/util/basic-types.h +++ b/src/app/util/basic-types.h @@ -32,5 +32,9 @@ namespace chip { typedef uint8_t Percent; typedef uint16_t Percent100ths; +typedef int64_t Energy_mWh; +typedef int64_t Amperage_mA; +typedef int64_t Power_mW; +typedef int64_t Voltage_mV; } // namespace chip diff --git a/src/python_testing/TC_EWATERHTR_2_1.py b/src/python_testing/TC_EWATERHTR_2_1.py index 055b5923cf6f07..df5d2821ece9e4 100644 --- a/src/python_testing/TC_EWATERHTR_2_1.py +++ b/src/python_testing/TC_EWATERHTR_2_1.py @@ -24,7 +24,7 @@ # test-runner-run/run1/factoryreset: True # test-runner-run/run1/quiet: True # test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x03 --application water-heater -# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto --int-arg PIXIT.EWATERHTR.EM:1 PIXIT.EWATERHTR.TP:2 +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # === END CI TEST ARGUMENTS === import logging @@ -50,20 +50,21 @@ def pics_TC_EWATERHTR_2_1(self): def steps_TC_EWATERHTR_2_1(self) -> list[TestStep]: steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads HeaterTypes attribute.", - "DUT as Server replies with a WaterHeaterHeatSourceBitmap (enum8) greater than 0x00 (at least one type supported), and less than 0x20 (no undefined types supported)."), - TestStep("3", "TH reads HeatDemand attribute.", - "DUT as Server replies with a WaterHeaterHeatSourceBitmap (enum8)."), - TestStep("4", "TH reads TankVolume attribute.", - "DUT as Server replies with a uint16 value."), - TestStep("5", "TH reads EstimatedHeatRequired attribute.", - "DUT as Server replies with an energy-mWh value."), - TestStep("6", "TH reads TankPercentage attribute.", - "DUT as Server replies with a percent value."), - TestStep("7", "TH reads BoostState attribute.", - "DUT as Server replies with a BoostStateEnum (enum8) value."), + TestStep("1", "Commission DUT to TH (can be skipped if done in a preceding test)."), + TestStep("2", "TH reads from the DUT the FeatureMap attribute.", + "Verify that the DUT response contains the FeatureMap attribute. Store the value as FeatureMap."), + TestStep("3", "TH reads from the DUT the HeaterTypes attribute.", + "Verify that the DUT response contains a WaterHeaterTypeBitmap (enum8) greater than 0x00 (at least one type supported), and less than 0x20 (no undefined types supported)"), + TestStep("4", "TH reads from the DUT the HeatDemand attribute.", + "Verify that the DUT response contains a WaterHeaterDemandBitmap (enum8) value less than 0x20 (no undefined types supported)."), + TestStep("5", "TH reads from the DUT the TankVolume attribute.", + "Verify that the DUT response contains a uint16 value."), + TestStep("6", "TH reads from the DUT the EstimatedHeatRequired attribute.", + "Verify that the DUT response contains an energy-mWh value that is greater or equal to 0."), + TestStep("7", "TH reads from the DUT the TankPercentage attribute.", + "Verify that the DUT response contains a percent value that is between 0 and 100 inclusive."), + TestStep("8", "TH reads from the DUT the BoostState attribute.", + "Verify that the DUT response contains a BoostStateEnum (enum8) value that is less than or equal to 1."), ] return steps @@ -71,40 +72,42 @@ def steps_TC_EWATERHTR_2_1(self) -> list[TestStep]: @async_test_body async def test_TC_EWATERHTR_2_1(self): - em_supported = self.matter_test_config.global_test_params['PIXIT.EWATERHTR.EM'] - tp_supported = self.matter_test_config.global_test_params['PIXIT.EWATERHTR.TP'] - self.step("1") # Commission DUT - already done + # Get the feature map for later self.step("2") + feature_map = await self.read_whm_attribute_expect_success(attribute="FeatureMap") + em_supported = bool(feature_map & Clusters.WaterHeaterManagement.Bitmaps.Feature.kEnergyManagement) + tp_supported = bool(feature_map & Clusters.WaterHeaterManagement.Bitmaps.Feature.kTankPercent) + logger.info(f"FeatureMap: {feature_map} : TP supported: {tp_supported} | EM supported: {em_supported}") + + self.step("3") heaterTypes = await self.read_whm_attribute_expect_success(attribute="HeaterTypes") asserts.assert_greater(heaterTypes, 0, f"Unexpected HeaterTypes value - expected {heaterTypes} > 0") asserts.assert_less_equal(heaterTypes, Clusters.WaterHeaterManagement.Bitmaps.WaterHeaterHeatSourceBitmap.kOther, f"Unexpected HeaterTypes value - expected {heaterTypes} <= WaterHeaterHeatSourceBitmap.kOther") - self.step("3") + self.step("4") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_greater(heatDemand, 0, - f"Unexpected HeatDemand value - expected {heatDemand} > 0") asserts.assert_less_equal(heatDemand, Clusters.WaterHeaterManagement.Bitmaps.WaterHeaterHeatSourceBitmap.kOther, f"Unexpected HeatDemand value - expected {heatDemand} <= WaterHeaterHeatSourceBitmap.kOther") - self.step("4") + self.step("5") if em_supported: value = await self.read_whm_attribute_expect_success(attribute="TankVolume") else: logging.info("Skipping step 4 as PIXIT.EWATERHTR.EM not supported") - self.step("5") + self.step("6") if em_supported: value = await self.read_whm_attribute_expect_success(attribute="EstimatedHeatRequired") asserts.assert_greater_equal(value, 0, f"Unexpected EstimatedHeatRequired value - expected {value} >= 0") else: logging.info("Skipping step 5 as PIXIT.EWATERHTR.EM not supported") - self.step("6") + self.step("7") if tp_supported: value = await self.read_whm_attribute_expect_success(attribute="TankPercentage") asserts.assert_greater_equal(value, 0, f"Unexpected TankPercentage value - expected {value} >= 0") @@ -112,9 +115,9 @@ async def test_TC_EWATERHTR_2_1(self): else: logging.info("Skipping step 6 as PIXIT.EWATERHTR.TP not supported") - self.step("7") + self.step("8") boost_state = await self.read_whm_attribute_expect_success(attribute="BoostState") - asserts.assert_less_equal(boost_state, Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive, + asserts.assert_less_equal(boost_state, Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive, f"Unexpected BoostState value - expected {boost_state} should be BoostStateEnum (enum8) value in range 0x00 to 0x01") diff --git a/src/python_testing/TC_EWATERHTR_2_2.py b/src/python_testing/TC_EWATERHTR_2_2.py index 5fd40e4130a64e..8c96e52d4524c8 100644 --- a/src/python_testing/TC_EWATERHTR_2_2.py +++ b/src/python_testing/TC_EWATERHTR_2_2.py @@ -32,7 +32,7 @@ import time import chip.clusters as Clusters -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_EWATERHTRBase import EWATERHTRBase @@ -52,119 +52,136 @@ def pics_TC_EWATERHTR_2_2(self): def steps_TC_EWATERHTR_2_2(self) -> list[TestStep]: steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify value is 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Basic installation Test Event.", - "Verify Command response is Success"), - TestStep("3a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("3b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("3c", "TH reads HeaterTypes attribute.", - "Verify value is greater than 0x00 (at least one type supported) and store the value as HeaterTypes"), - TestStep("4", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Manual mode Test Event.", - "Verify Command response is Success"), - TestStep("4a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("5a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 20C Test Event.", - "Verify Command response is Success"), - TestStep("6a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source)"), - TestStep("7", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Off mode Test Event.", - "Verify Command response is Success"), - TestStep("7a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("8", "TH sends Boost with Duration=5s,OneShot=True.", - "Verify Command response is Success"), - TestStep("8a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("8b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("9", "Wait 6 seconds"), - TestStep("9a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("9b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("10", "TH sends Boost with Duration=600s,OneShot=True.", - "Verify Command response is Success"), - TestStep("10a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("10b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("11a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("11b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("12", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 20C Test Event.", - "Verify Command response is Success"), - TestStep("12a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("13", "TH sends Boost with Duration=600s.", - "Verify Command response is Success"), - TestStep("13a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("13b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("14a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("14b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 20C Test Event.", - "Verify Command response is Success"), - TestStep("15a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("15b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("16", "TH sends CancelBoost.", - "Verify Command response is Success"), - TestStep("16a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("16b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("17", "TH sends Boost with Duration=600s,TemporarySetpoint=65C.", - "Verify Command response is Success"), - TestStep("17a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("17b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("18a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("18b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 66C Test Event.", - "Verify Command response is Success"), - TestStep("19a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("19b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("20", "TH sends Boost with Duration=600s,TemporarySetpoint=70C.", - "Verify Command response is Success"), - TestStep("20a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("20b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("21", "TH sends CancelBoost.", - "Verify Command response is Success"), - TestStep("21a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("21b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("22", "TH sends CancelBoost.", - "Verify Command response is Success"), - TestStep("23", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Basic installation Test Event Clear.", - "Verify Command response is Success"), + TestStep("1", "Commission DUT to TH (can be skipped if done in a preceding test)"), + TestStep("2", "Set up a subscription to all WaterHeaterManagement cluster events"), + TestStep("3", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster", + "Value has to be 1 (True)"), + TestStep("4", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Basic installation Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("4b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("4c", "TH reads from the DUT the HeaterTypes", + "Value has to be greater than 0x00 (at least one type supported) and Store the value as HeaterTypes"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Manual mode Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("5a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("6a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("7", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 20C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("7a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source)"), + TestStep("8", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Off mode Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("8a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("9", "TH sends command Boost with Duration=5s,OneShot=True", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=5 and OneShot=True"), + TestStep("9a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("9b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("10", "Wait 6 seconds", + "Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("10a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("10b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("11", "TH sends command Boost with Duration=600s,OneShot=True", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=600 and OneShot=True"), + TestStep("11a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("11b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("12", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("12a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("12b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 20C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("13a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("14", "TH sends command Boost with Duration=600s", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=600 and OneShot=None"), + TestStep("14a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("14b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("15a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("15b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 20C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("16a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("16b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("17", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("17a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("17b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("18", "TH sends command Boost with Duration=500s,TemporarySetpoint=65C", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=500 and TemporarySetpoint=6500"), + TestStep("18a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("18b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("19a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("19b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("20", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 66C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("20a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("20b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("21", "TH sends command Boost with Duration=600s,TemporarySetpoint=70C", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=600 and TemporarySetpoint=7000"), + TestStep("21a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("21b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("22", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("22a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("22b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("23", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 20C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("23a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("24", "TH sends command Boost with Duration=200s,EmergencyBoost=True", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=200, EmergencyBoost=True and TemporarySetpoint=None"), + TestStep("24a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("24b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("25", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("25a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("25b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("26", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and no event sent"), + TestStep("27", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Basic installation Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -176,202 +193,273 @@ async def test_TC_EWATERHTR_2_2(self): # Commission DUT - already done self.step("2") - await self.check_test_event_triggers_enabled() + # Subscribe to Events and when they are sent push them to a queue for checking later + events_callback = EventChangeCallback(Clusters.WaterHeaterManagement) + await events_callback.start(self.default_controller, + self.dut_node_id, + self.matter_test_config.endpoint) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_basic_installation_test_event() - self.step("3a") + self.step("4a") await self.check_whm_attribute("HeatDemand", 0) - self.step("3b") + self.step("4b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("3c") + self.step("4c") heaterTypes = await self.read_whm_attribute_expect_success(attribute="HeaterTypes") asserts.assert_greater(heaterTypes, 0, f"Unexpected HeaterTypes value - expected {heaterTypes} > 0") asserts.assert_less_equal(heaterTypes, Clusters.WaterHeaterManagement.Bitmaps.WaterHeaterHeatSourceBitmap.kOther, f"Unexpected HeaterTypes value - expected {heaterTypes} <= WaterHeaterHeatSourceBitmap.kOther") - self.step("4") + self.step("5") await self.send_test_event_trigger_manual_mode_test_event() - self.step("4a") + self.step("5a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("5") + self.step("6") await self.send_test_event_trigger_water_temperature61C_test_event() - self.step("5a") + self.step("6a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("6") + self.step("7") await self.send_test_event_trigger_water_temperature20C_test_event() - self.step("6a") + self.step("7a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("7") + self.step("8") await self.send_test_event_trigger_off_mode_test_event() - self.step("7a") + self.step("8a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("8") + self.step("9") await self.send_boost_command(duration=5, one_shot=True) - self.step("8a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 5) + asserts.assert_equal(event_data.boostInfo.oneShot, True) + + self.step("9a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("8b") + self.step("9b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("9") + self.step("10") time.sleep(6) + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) - self.step("9a") + self.step("10a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("9b") + self.step("10b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("10") + self.step("11") await self.send_boost_command(duration=600, one_shot=True) - self.step("10a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 600) + asserts.assert_equal(event_data.boostInfo.oneShot, True) + + self.step("11a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("10b") + self.step("11b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("11") + self.step("12") await self.send_test_event_trigger_water_temperature61C_test_event() - self.step("11a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) + + self.step("12a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("11b") + self.step("12b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("12") + self.step("13") await self.send_test_event_trigger_water_temperature20C_test_event() - self.step("12a") + self.step("13a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("13") + self.step("14") await self.send_boost_command(duration=600) - self.step("13a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 600) + asserts.assert_true(event_data.boostInfo.oneShot is None, "oneShot should be None") + + self.step("14a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("13b") + self.step("14b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("14") + self.step("15") await self.send_test_event_trigger_water_temperature61C_test_event() - self.step("14a") + self.step("15a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("14b") + self.step("15b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("15") + self.step("16") await self.send_test_event_trigger_water_temperature20C_test_event() - self.step("15a") + self.step("16a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("15b") + self.step("16b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("16") + self.step("17") await self.send_cancel_boost_command() - self.step("16a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) + + self.step("17a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("16b") + self.step("17b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("17") - await self.send_boost_command(duration=600, temporary_setpoint=6500) + self.step("18") + await self.send_boost_command(duration=500, temporary_setpoint=6500) - self.step("17a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 500) + asserts.assert_equal(event_data.boostInfo.temporarySetpoint, 6500) + + self.step("18a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("17b") + self.step("18b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("18") + self.step("19") await self.send_test_event_trigger_water_temperature61C_test_event() - self.step("18a") + self.step("19a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("18b") + self.step("19b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("19") + self.step("20") await self.send_test_event_trigger_water_temperature66C_test_event() - self.step("19a") + self.step("20a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("19b") + self.step("20b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("20") + self.step("21") await self.send_boost_command(duration=600, temporary_setpoint=7000) - self.step("20a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 600) + asserts.assert_equal(event_data.boostInfo.temporarySetpoint, 7000) + + self.step("21a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_greater(heatDemand, 0) asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - self.step("20b") + self.step("21b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("21") + self.step("22") await self.send_cancel_boost_command() - self.step("21a") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) + + self.step("22a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") asserts.assert_equal(heatDemand, 0) - self.step("21b") + self.step("22b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("22") + self.step("23") + await self.send_test_event_trigger_water_temperature20C_test_event() + + self.step("23a") + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_equal(heatDemand, 0) + + self.step("24") + await self.send_boost_command(duration=200, emergency_boost=True) + + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 200) + asserts.assert_equal(event_data.boostInfo.emergencyBoost, True) + asserts.assert_is_none(event_data.boostInfo.temporarySetpoint) + + self.step("24a") + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_greater(heatDemand, 0) + asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), + + self.step("24b") + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) + + self.step("25") await self.send_cancel_boost_command() - self.step("23") + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) + + self.step("25a") + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_equal(heatDemand, 0) + + self.step("25b") + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) + + self.step("26") + await self.send_cancel_boost_command() + + event_data = events_callback.wait_for_event_expect_no_report() + + self.step("27") await self.send_test_event_trigger_basic_installation_test_event_clear() diff --git a/src/python_testing/TC_EWATERHTR_2_3.py b/src/python_testing/TC_EWATERHTR_2_3.py index d2bc97d33b5113..e39257134b3db5 100644 --- a/src/python_testing/TC_EWATERHTR_2_3.py +++ b/src/python_testing/TC_EWATERHTR_2_3.py @@ -30,7 +30,7 @@ import logging import chip.clusters as Clusters -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_EWATERHTRBase import EWATERHTRBase @@ -49,92 +49,92 @@ def pics_TC_EWATERHTR_2_3(self): def steps_TC_EWATERHTR_2_3(self) -> list[TestStep]: steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify value is 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Basic installation Test Event.", - "Verify Command response is Success"), - TestStep("3a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("3b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("3c", "TH reads TankPercentage attribute.", - "Verify value is 0%"), - TestStep("3d", "TH reads HeaterTypes attribute.", - "Verify value is greater than 0x00 (at least one type supported) and store the value as HeaterTypes"), - TestStep("4", "TH sends Boost with Duration=600s,TargetPercentage=100%.", - "Verify Command response is Success"), - TestStep("4a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("4b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("5a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("5b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("5c", "TH reads TankPercentage attribute.", - "Verify value is 100%"), - TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Draw off hot water Test Event.", - "Verify Command response is Success"), - TestStep("6a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("6b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("6c", "TH reads TankPercentage attribute.", - "Verify value is 75%"), - TestStep("7", "TH sends CancelBoost.", - "Verify Command response is Success"), - TestStep("7a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("7b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("7c", "TH reads TankPercentage attribute.", - "Verify value is 75%"), - TestStep("8", "TH sends Boost with Duration=600s,TargetPercentage=100%,TargetReheat=65%.", - "Verify Command response is Success"), - TestStep("8a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("8b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("8c", "TH reads TankPercentage attribute.", - "Verify value is 75%"), - TestStep("9", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Water Temperature 61C Test Event.", - "Verify Command response is Success"), - TestStep("9a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("9b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("9c", "TH reads TankPercentage attribute.", - "Verify value is 100%"), - TestStep("10", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Draw off hot water Test Event.", - "Verify Command response is Success"), - TestStep("10a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("10b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("10c", "TH reads TankPercentage attribute.", - "Verify value is 75%"), - TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Draw off hot water Test Event.", - "Verify Command response is Success"), - TestStep("11a", "TH reads HeatDemand attribute.", - "Verify value is greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), - TestStep("11b", "TH reads BoostState attribute.", - "Verify value is 1 (Active)"), - TestStep("11c", "TH reads TankPercentage attribute.", - "Verify value is 50%"), - TestStep("12", "TH sends CancelBoost.", - "Verify Command response is Success"), - TestStep("12a", "TH reads HeatDemand attribute.", - "Verify value is 0x00 (no demand on any source)"), - TestStep("12b", "TH reads BoostState attribute.", - "Verify value is 0 (Inactive)"), - TestStep("12c", "TH reads TankPercentage attribute.", - "Verify value is 50%"), - TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EWATERHTR.TEST_EVENT_TRIGGER for Basic installation Test Event Clear.", - "Verify Command response is Success"), + TestStep("1", "Commission DUT to TH (can be skipped if done in a preceding test)"), + TestStep("2", "Set up a subscription to all WaterHeaterManagement cluster events"), + TestStep("3", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster", + "Value has to be 1 (True)"), + TestStep("4", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Basic installation Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("4b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("4c", "TH reads from the DUT the TankPercentage", + "Value has to be 0%"), + TestStep("4d", "TH reads from the DUT the HeaterTypes", + "Value has to be greater than 0x00 (at least one type supported) and Store the value as HeaterTypes"), + TestStep("5", "TH sends command Boost with Duration=600s,TargetPercentage=100%", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=600 and TargetPercentage=100"), + TestStep("5a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("5b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("6a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("6b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("6c", "TH reads from the DUT the TankPercentage", + "Value has to be 100%"), + TestStep("7", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Draw off hot water Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("7a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("7b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("7c", "TH reads from the DUT the TankPercentage", + "Value has to be 76%"), + TestStep("8", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("8a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("8b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("8c", "TH reads from the DUT the TankPercentage", + "Value has to be 76%"), + TestStep("9", "TH sends command Boost with Duration=400s,TargetPercentage=100%,TargetReheat=65%", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostStarted) sent with Duration=400 and TargetPercentage=100 and TargetReheat=65"), + TestStep("9a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("9b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("9c", "TH reads from the DUT the TankPercentage", + "Value has to be 76%"), + TestStep("10", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Water Temperature 61C Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("10a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("10b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("10c", "TH reads from the DUT the TankPercentage", + "Value has to be 100%"), + TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Draw off hot water Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("11a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("11b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("11c", "TH reads from the DUT the TankPercentage", + "Value has to be 76%"), + TestStep("12", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Draw off hot water Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("12a", "TH reads from the DUT the HeatDemand", + "Value has to be greater than 0x00 (demand on at least one source) and (HeaterDemand & (!HeaterTypes)) is zero (demand is only from declared supported types)"), + TestStep("12b", "TH reads from the DUT the BoostState", + "Value has to be 1 (Active)"), + TestStep("12c", "TH reads from the DUT the TankPercentage", + "Value has to be 57%"), + TestStep("13", "TH sends command CancelBoost", + "Verify DUT responds w/ status SUCCESS(0x00) and Event EWATERHTR.S.E00(BoostEnded) sent"), + TestStep("13a", "TH reads from the DUT the HeatDemand", + "Value has to be 0x00 (no demand on any source)"), + TestStep("13b", "TH reads from the DUT the BoostState", + "Value has to be 0 (Inactive)"), + TestStep("13c", "TH reads from the DUT the TankPercentage", + "Value has to be 57%"), + TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EWATERHTR.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.EWATERHTR.TESTEVENTTRIGGER for Basic installation Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -146,102 +146,108 @@ async def test_TC_EWATERHTR_2_3(self): # Commission DUT - already done self.step("2") - await self.check_test_event_triggers_enabled() + # Subscribe to Events and when they are sent push them to a queue for checking later + events_callback = EventChangeCallback(Clusters.WaterHeaterManagement) + await events_callback.start(self.default_controller, + self.dut_node_id, + self.matter_test_config.endpoint) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_basic_installation_test_event() - self.step("3a") + self.step("4a") await self.check_whm_attribute("HeatDemand", 0) - self.step("3b") + self.step("4b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) - self.step("3c") + self.step("4c") await self.check_whm_attribute("TankPercentage", 0) - self.step("3d") + self.step("4d") heaterTypes = await self.read_whm_attribute_expect_success(attribute="HeaterTypes") asserts.assert_greater(heaterTypes, 0) - self.step("4") + self.step("5") await self.send_boost_command(duration=600, target_percentage=100) - self.step("4a") - heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_greater(heatDemand, 0) - asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), - - self.step("4b") - await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - - self.step("5") - await self.send_test_event_trigger_water_temperature61C_test_event() + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 600) + asserts.assert_equal(event_data.boostInfo.targetPercentage, 100) self.step("5a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_equal(heatDemand, 0) + asserts.assert_greater(heatDemand, 0) + asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), self.step("5b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) - self.step("5c") - await self.check_whm_attribute("TankPercentage", 100) - self.step("6") - await self.send_test_event_trigger_draw_off_hot_water_test_event() + await self.send_test_event_trigger_water_temperature61C_test_event() self.step("6a") heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_greater(heatDemand, 0) - asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), + asserts.assert_equal(heatDemand, 0) self.step("6b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("6c") - await self.check_whm_attribute("TankPercentage", 75) + await self.check_whm_attribute("TankPercentage", 100) self.step("7") - await self.send_cancel_boost_command() + await self.send_test_event_trigger_draw_off_hot_water_test_event() self.step("7a") - await self.check_whm_attribute("HeatDemand", 0) + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_greater(heatDemand, 0) + asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), self.step("7b") - await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("7c") - await self.check_whm_attribute("TankPercentage", 75) + await self.check_whm_attribute("TankPercentage", 76) self.step("8") - await self.send_boost_command(duration=600, target_percentage=100, target_reheat=65) + await self.send_cancel_boost_command() + + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) self.step("8a") - heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_greater(heatDemand, 0) - asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), + await self.check_whm_attribute("HeatDemand", 0) self.step("8b") - await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) self.step("8c") - await self.check_whm_attribute("TankPercentage", 75) + await self.check_whm_attribute("TankPercentage", 76) self.step("9") - await self.send_test_event_trigger_water_temperature61C_test_event() + await self.send_boost_command(duration=400, target_percentage=100, target_reheat=65) + + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostStarted) + asserts.assert_equal(event_data.boostInfo.duration, 400) + asserts.assert_equal(event_data.boostInfo.targetPercentage, 100) + asserts.assert_equal(event_data.boostInfo.targetReheat, 65) self.step("9a") - await self.check_whm_attribute("HeatDemand", 0) + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_greater(heatDemand, 0) + asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), self.step("9b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("9c") - await self.check_whm_attribute("TankPercentage", 100) + await self.check_whm_attribute("TankPercentage", 76) self.step("10") - await self.send_test_event_trigger_draw_off_hot_water_test_event() + await self.send_test_event_trigger_water_temperature61C_test_event() self.step("10a") await self.check_whm_attribute("HeatDemand", 0) @@ -250,35 +256,49 @@ async def test_TC_EWATERHTR_2_3(self): await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("10c") - await self.check_whm_attribute("TankPercentage", 75) + await self.check_whm_attribute("TankPercentage", 100) self.step("11") await self.send_test_event_trigger_draw_off_hot_water_test_event() self.step("11a") - heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") - asserts.assert_greater(heatDemand, 0) - asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), + await self.check_whm_attribute("HeatDemand", 0) self.step("11b") await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("11c") - await self.check_whm_attribute("TankPercentage", 50) + await self.check_whm_attribute("TankPercentage", 76) self.step("12") - await self.send_cancel_boost_command() + await self.send_test_event_trigger_draw_off_hot_water_test_event() self.step("12a") - await self.check_whm_attribute("HeatDemand", 0) + heatDemand = await self.read_whm_attribute_expect_success(attribute="HeatDemand") + asserts.assert_greater(heatDemand, 0) + asserts.assert_equal(heatDemand & (~heaterTypes), 0, "heatDemand should only be from declared supported types"), self.step("12b") - await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive) self.step("12c") - await self.check_whm_attribute("TankPercentage", 50) + await self.check_whm_attribute("TankPercentage", 57) self.step("13") + await self.send_cancel_boost_command() + + event_data = events_callback.wait_for_event_report(Clusters.WaterHeaterManagement.Events.BoostEnded) + + self.step("13a") + await self.check_whm_attribute("HeatDemand", 0) + + self.step("13b") + await self.check_whm_attribute("BoostState", Clusters.WaterHeaterManagement.Enums.BoostStateEnum.kInactive) + + self.step("13c") + await self.check_whm_attribute("TankPercentage", 57) + + self.step("14") await self.send_test_event_trigger_basic_installation_test_event_clear()