From 43326f304e55fd5530680794bc0ef219b4f5d04a Mon Sep 17 00:00:00 2001 From: PeterC1965 <101805108+PeterC1965@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:29:24 +0100 Subject: [PATCH] Address various DEM testing issues (#35067) * Add checks for correct DEM feature map for test * Add checks for a nominalPower having a value and get slotIndex check correct * Allow a little tolerance checking the duration returned in the event as CI tests can run slower * Restyled by clang-format * Restyled by autopep8 * Add check DEM feature map step + add event registration step if necessary and renumber test cases * Fix issue #4415 Fails randomly on CI when checking pause duration * Test an illegal slot index == number of slots in a forecast * Add a test in PFR when ModifyForecastRequest does not specify NominalPower * Set ClusterRevision to 4 * First versionof DEM 1-1 * Regenerate files * Get DEM 1.1 test passing * Update test step definitions * Get featureSet option correct * Restyled by autopep8 * First cut of a Q quality test * Regenerate files following a re-bootstrap * Fix typo in comment * Cancel subscriptions at the end of the test * Add a cancel subscription method * Ensure MatterReportingAttributeChangeCallback is called after forecast is changed * Restyled by autopep8 * Restyled by isort * Fix ruff detected errors * Restyled by autopep8 * Fix the cancelling of subscriptions * Used .name instead of needing a feature string mapping. * Removed TC_DEM_1_1 now that the test plan has removed this test case. * Corrected Featuremap -> FeatureMap in test steps * Aligned verification step 2 on TC_DEM_2.3 to actual code and syncd test plan. * Aligned verification step 2 on TC_DEM_2.4 to actual code and syncd test plan. * Added in missing text in step 18 in TC_DEM_2.4 * TC_DEM_2.5 minor update to step 2 and aligning to updated test plan. * TC_DEM_2.5 - slight change to call to name args in validate_feature_map() call * TC_DEM_2.6,2.7,2.8 step 2 alignment with tweaked test plan * TC_DEM_2.6/2.7/2.8 - slight change to call to name args in validate_feature_map() call * Corrected log message in TC_DEM_2.9 step 4b * Updated TC_DEM_2.10 (Q Quality) Basic structure is there - steps need tidying up and fails due to powerAdjustmentCapability not being updated as expected. * Fixed bug where PowerAdjustReason wasn't calling MatterReportingAttributeChangeCallback when reason was changing. * Restyled by clang-format * Restyled by autopep8 * Restyled by isort * Autogen'd the TestSteps from latest test plan * Changed featureSet to 0x7b to enable PA, PFR, FA (plus other) features --------- Co-authored-by: Restyled.io Co-authored-by: James Harrow Co-authored-by: Hasty Granbery --- .../DeviceEnergyManagementDelegateImpl.h | 1 + .../DeviceEnergyManagementDelegateImpl.cpp | 27 +- .../energy-management-app.matter | 2 +- .../energy-management-app.zap | 2 +- .../device-energy-management-server.cpp | 6 +- src/python_testing/TC_DEMTestBase.py | 20 ++ src/python_testing/TC_DEM_2_10.py | 296 ++++++++++++++++++ src/python_testing/TC_DEM_2_2.py | 232 +++++++------- src/python_testing/TC_DEM_2_3.py | 211 +++++++------ src/python_testing/TC_DEM_2_4.py | 275 ++++++++-------- src/python_testing/TC_DEM_2_5.py | 229 +++++++------- src/python_testing/TC_DEM_2_6.py | 206 ++++++------ src/python_testing/TC_DEM_2_7.py | 226 ++++++------- src/python_testing/TC_DEM_2_8.py | 206 ++++++------ src/python_testing/TC_DEM_2_9.py | 46 ++- src/python_testing/matter_testing_support.py | 13 +- 16 files changed, 1177 insertions(+), 821 deletions(-) create mode 100644 src/python_testing/TC_DEM_2_10.py diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/include/DeviceEnergyManagementDelegateImpl.h b/examples/energy-management-app/energy-management-common/device-energy-management/include/DeviceEnergyManagementDelegateImpl.h index e540d56e030058..da563910f749c7 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/include/DeviceEnergyManagementDelegateImpl.h +++ b/examples/energy-management-app/energy-management-common/device-energy-management/include/DeviceEnergyManagementDelegateImpl.h @@ -189,6 +189,7 @@ class DeviceEnergyManagementDelegate : public DeviceEnergyManagement::Delegate CHIP_ERROR SetAbsMinPower(int64_t); CHIP_ERROR SetAbsMaxPower(int64_t); CHIP_ERROR SetPowerAdjustmentCapability(const DataModel::Nullable &); + CHIP_ERROR SetPowerAdjustmentCapabilityPowerAdjustReason(const PowerAdjustReasonEnum); // The DeviceEnergyManagementDelegate owns the master copy of the ForecastStruct object which is accessed via GetForecast and // SetForecast. The slots field of forecast is owned and managed by the object that implements the DEMManufacturerDelegate 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 161ea2f77c0750..157b85d4773f5f 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 @@ -120,11 +120,11 @@ Status DeviceEnergyManagementDelegate::PowerAdjustRequest(const int64_t powerMw, switch (cause) { case AdjustmentCauseEnum::kLocalOptimization: - mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kLocalOptimizationAdjustment; + SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum::kLocalOptimizationAdjustment); break; case AdjustmentCauseEnum::kGridOptimization: - mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kGridOptimizationAdjustment; + SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum::kGridOptimizationAdjustment); break; default: @@ -175,7 +175,7 @@ void DeviceEnergyManagementDelegate::HandlePowerAdjustRequestFailure() mPowerAdjustmentInProgress = false; - mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum::kNoAdjustment); // TODO // Should we inform the mpDEMManufacturerDelegate that PowerAdjustRequest has failed? @@ -210,7 +210,7 @@ void DeviceEnergyManagementDelegate::HandlePowerAdjustTimerExpiry() SetESAState(ESAStateEnum::kOnline); - mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum::kNoAdjustment); // Generate a PowerAdjustEnd event GeneratePowerAdjustEndEvent(CauseEnum::kNormalCompletion); @@ -264,8 +264,7 @@ CHIP_ERROR DeviceEnergyManagementDelegate::CancelPowerAdjustRequestAndGenerateEv SetESAState(ESAStateEnum::kOnline); mPowerAdjustmentInProgress = false; - - mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum::kNoAdjustment); CHIP_ERROR err = GeneratePowerAdjustEndEvent(cause); @@ -922,6 +921,18 @@ DeviceEnergyManagementDelegate::SetPowerAdjustmentCapability( return CHIP_NO_ERROR; } +CHIP_ERROR +DeviceEnergyManagementDelegate::SetPowerAdjustmentCapabilityPowerAdjustReason(PowerAdjustReasonEnum powerAdjustReason) +{ + assertChipStackLockedByCurrentThread(); + + mPowerAdjustCapabilityStruct.Value().cause = powerAdjustReason; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, PowerAdjustmentCapability::Id); + + return CHIP_NO_ERROR; +} + CHIP_ERROR DeviceEnergyManagementDelegate::SetForecast(const DataModel::Nullable & forecast) { assertChipStackLockedByCurrentThread(); @@ -962,9 +973,9 @@ CHIP_ERROR DeviceEnergyManagementDelegate::SetOptOutState(OptOutStateEnum newVal if (mPowerAdjustmentInProgress) { if ((newValue == OptOutStateEnum::kLocalOptOut && - mPowerAdjustCapabilityStruct.Value().cause == PowerAdjustReasonEnum::kLocalOptimizationAdjustment) || + GetPowerAdjustmentCapability().Value().cause == PowerAdjustReasonEnum::kLocalOptimizationAdjustment) || (newValue == OptOutStateEnum::kGridOptOut && - mPowerAdjustCapabilityStruct.Value().cause == PowerAdjustReasonEnum::kGridOptimizationAdjustment) || + GetPowerAdjustmentCapability().Value().cause == PowerAdjustReasonEnum::kGridOptimizationAdjustment) || newValue == OptOutStateEnum::kOptOut) { err = CancelPowerAdjustRequestAndGenerateEvent(DeviceEnergyManagement::CauseEnum::kUserOptOut); 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 faf05b7c182995..c3401388bae96e 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 @@ -2704,7 +2704,7 @@ endpoint 1 { callback attribute eventList; callback attribute attributeList; callback attribute featureMap; - ram attribute clusterRevision default = 3; + ram attribute clusterRevision default = 4; handle command PowerAdjustRequest; handle command CancelPowerAdjustRequest; 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 1a312c93abed59..17a539dbf13348 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 @@ -4210,7 +4210,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "3", + "defaultValue": "4", "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp index 438e2d7bd5f7d3..0b7205dd83a33a 100644 --- a/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp +++ b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp @@ -676,7 +676,7 @@ void Instance::HandleModifyForecastRequest(HandlerContext & ctx, const Commands: const Structs::SlotAdjustmentStruct::Type & slotAdjustment = iterator.GetValue(); // Check for an invalid slotIndex - if (slotAdjustment.slotIndex > forecast.Value().slots.size()) + if (slotAdjustment.slotIndex >= forecast.Value().slots.size()) { ChipLogError(Zcl, "DEM: Bad slot index %d", slotAdjustment.slotIndex); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); @@ -696,8 +696,8 @@ void Instance::HandleModifyForecastRequest(HandlerContext & ctx, const Commands: // NominalPower is only relevant if PFR is supported if (HasFeature(Feature::kPowerForecastReporting)) { - if (!slot.minPowerAdjustment.HasValue() || !slot.maxPowerAdjustment.HasValue() || - slotAdjustment.nominalPower.Value() < slot.minPowerAdjustment.Value() || + if (!slotAdjustment.nominalPower.HasValue() || !slot.minPowerAdjustment.HasValue() || + !slot.maxPowerAdjustment.HasValue() || slotAdjustment.nominalPower.Value() < slot.minPowerAdjustment.Value() || slotAdjustment.nominalPower.Value() > slot.maxPowerAdjustment.Value()) { ChipLogError(Zcl, "DEM: Bad nominalPower"); diff --git a/src/python_testing/TC_DEMTestBase.py b/src/python_testing/TC_DEMTestBase.py index db53c36f8cd1c9..da51ba252820cc 100644 --- a/src/python_testing/TC_DEMTestBase.py +++ b/src/python_testing/TC_DEMTestBase.py @@ -38,6 +38,26 @@ async def check_dem_attribute(self, attribute, expected_value, endpoint: int = N asserts.assert_equal(value, expected_value, f"Unexpected '{attribute}' value - expected {expected_value}, was {value}") + async def validate_feature_map(self, must_have_features, must_not_have_features): + feature_map = await self.read_dem_attribute_expect_success(attribute="FeatureMap") + for must_have_feature in must_have_features: + asserts.assert_true(feature_map & must_have_feature, + f"{must_have_feature.name} must be set but is not. feature_map 0x{feature_map:x}") + + for must_not_have_feature in must_not_have_features: + asserts.assert_false(feature_map & must_not_have_feature, + f"{must_not_have_feature.name} is not allowed to be set. feature_map 0x{feature_map:x}") + + async def validate_pfr_or_sfr_in_feature_map(self): + feature_map = await self.read_dem_attribute_expect_success(attribute="FeatureMap") + + illegal_combination = Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting | Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting + asserts.assert_not_equal(feature_map & illegal_combination, illegal_combination, + f"Cannot have kPowerForecastReporting and kStateForecastReporting both set. feature_map 0x{feature_map:x}") + + asserts.assert_not_equal(feature_map & illegal_combination, 0, + f"Must have one of kPowerForecastReporting and kStateForecastReporting set. feature_map 0x{feature_map:x}") + async def send_power_adjustment_command(self, power: int, duration: int, cause: Clusters.Objects.DeviceEnergyManagement.Enums.CauseEnum, endpoint: int = None, timedRequestTimeoutMs: int = 3000, diff --git a/src/python_testing/TC_DEM_2_10.py b/src/python_testing/TC_DEM_2_10.py new file mode 100644 index 00000000000000..eb983a16e07401 --- /dev/null +++ b/src/python_testing/TC_DEM_2_10.py @@ -0,0 +1,296 @@ +# +# 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. +# pylint: disable=invalid-name + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} +# 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 0x7b +# 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 === + +"""Define Matter test case TC_DEM_2_10.""" + + +import logging +import sys +import time + +import chip.clusters as Clusters +from chip.interaction_model import Status +from matter_testing_support import (ClusterAttributeChangeAccumulator, MatterBaseTest, TestStep, async_test_body, + default_matter_test_main) +from mobly import asserts +from TC_DEMTestBase import DEMTestBase + +logger = logging.getLogger(__name__) + + +class TC_DEM_2_10(MatterBaseTest, DEMTestBase): + """Implementation of test case TC_DEM_2_10.""" + + def desc_TC_DEM_2_10(self) -> str: + """Return a description of this test.""" + return "4.1.3. [TC-DEM-2.10] This test case verifies attributes of the Device Energy Mangement cluster server having the Q quality." + + def pics_TC_DEM_2_10(self): + """Return the PICS definitions associated with this test.""" + pics = [ + "DEM.S" + ] + return pics + + def steps_TC_DEM_2_10(self) -> list[TestStep]: + """Execute the test steps.""" + steps = [ + TestStep("1", "Commission DUT to TH (can be skipped if done in a preceding test)"), + TestStep("2", "TH reads from the DUT the FeatureMap", + "Verify that the DUT response contains the FeatureMap attribute. Store the value as FeatureMap."), + TestStep("3", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster", + "Value has to be 1 (True)"), + TestStep("4", "Set up a subscription to the DeviceEnergyManagement cluster, with MinIntervalFloor set to 0, MaxIntervalCeiling set to 10 and KeepSubscriptions set to false", + "Subscription successfully established"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.DEM.TESTEVENTTRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("5a", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("6", "If ForecastAdjustment feature is not supported on the cluster skip steps 7 to 14"), + TestStep("7", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.DEM.TESTEVENTTRIGGER for Forecast Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("7a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("8", "Reset all accumulated report counts, then wait 12 seconds"), + TestStep("9", "TH counts all report transactions with an attribute report for the Forecast attribute", + "TH verifies that numberOfReportsReceived <= 2"), + TestStep("10", "TH reads from the DUT the Forecast", + "Value has to include slots[0].MinDurationAdjustment, slots[0].MaxDurationAdjustment"), + TestStep("11", "If PowerForecastReporting feature is supported on the cluster TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment, NominalPower=forecast.slots[0].minPowerAdjustment}, Cause=GridOptimization, else StateForecastReporting shall be used, omit the NominalPower: TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("12", "TH resets all accumulated report counts, then TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("13", "Wait 5 seconds"), + TestStep("13a", "TH counts all report transactions with an attribute report for the Forecast attribute", + "TH verifies that numberOfReportsReceived >= 1"), + TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.DEM.TESTEVENTTRIGGER for Forecast Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("15", "If PowerAdjustment feature is not supported on the cluster skip steps 16 to 21"), + TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.DEM.TESTEVENTTRIGGER for Power Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("16b", "TH reads from the DUT the PowerAdjustmentCapability", + "Value has to include Cause=NoAdjustment."), + TestStep("17", "TH resets all accumulated report counts, then TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=20, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("18", "Wait 12 seconds"), + TestStep("18a", "TH counts all report transactions with an attribute report for the PowerAdjustmentCapability attribute", + "TH verifies that numberOfReportsReceived <= 2"), + TestStep("19", "TH resets all accumulated report counts, then TH sends command CancelPowerAdjustment", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("20", "Wait 5 seconds"), + TestStep("20a", "TH counts all report transactions with an attribute report for the PowerAdjustmentCapability attribute", + "TH verifies that numberOfReportsReceived >=1"), + TestStep("21", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TESTEVENT_TRIGGERKEY and EventTrigger field set to PIXIT.DEM.TESTEVENTTRIGGER for Power Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("22", "Cancel the subscription to the Device Energy Management cluster", + "The subscription is cancelled successfully"), + ] + + return steps + + @ async_test_body + async def test_TC_DEM_2_10(self): + # pylint: disable=too-many-locals, too-many-statements + """Run the test steps.""" + self.step("1") + # Commission DUT - already done + + self.step("2") + feature_map = await self.read_dem_attribute_expect_success(attribute="FeatureMap") + logger.info(f"FeatureMap: {feature_map}") + + has_pfr = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting + has_sfr = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting + has_pa = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerAdjustment + has_sta = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStartTimeAdjustment + has_pau = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPausable + has_fa = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kForecastAdjustment + has_con = feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kConstraintBasedAdjustment + has_any_forecast_adjustment = has_sta | has_pau | has_fa | has_con + if has_any_forecast_adjustment: + # check it has pfr or sfr (one not both) + asserts.assert_false(has_pfr and has_sfr, "Not allowed to have both PFR and SFR features enabled!") + asserts.assert_true(has_pfr or has_sfr, "Must have either PFR or SFR with a forecast adjustment feature") + + if has_pa: + asserts.assert_true(has_pfr, "Since PowerAdjustment is supported, PFR should be used, not SFR") + + self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") + sub_handler = ClusterAttributeChangeAccumulator(Clusters.DeviceEnergyManagement) + await sub_handler.start(self.default_controller, self.dut_node_id, + self.matter_test_config.endpoint, + min_interval_sec=0, + max_interval_sec=10, keepSubscriptions=False) + + def accumulate_reports(wait_time): + logging.info(f"Test will now wait {wait_time} seconds to accumulate reports") + time.sleep(wait_time) + + self.step("5") + await self.send_test_event_trigger_user_opt_out_clear_all() + + self.step("5a") + await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) + + self.step("6") + if not has_fa: + self.skip_step("7") + self.skip_step("7a") + self.skip_step("8") + self.skip_step("9") + self.skip_step("10") + self.skip_step("11") + self.skip_step("12") + self.skip_step("13") + self.skip_step("13a") + self.skip_step("14") + else: + self.step("7") + await self.send_test_event_trigger_forecast_adjustment() + + self.step("7a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("8") + wait = 12 # Wait 12 seconds - the spec says we should only get reports every 10s at most, unless a command changes it + sub_handler.reset() + accumulate_reports(wait) + + self.step("9") + count = sub_handler.attribute_report_counts[Clusters.DeviceEnergyManagement.Attributes.Forecast] + logging.info(f"Received {count} Forecast updates in {wait} seconds") + asserts.assert_less_equal(count, 2, f"Expected <= 2 Forecast updates in {wait} seconds") + + self.step("10") + forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") + asserts.assert_is_not_none(forecast.slots[0].minDurationAdjustment) + asserts.assert_is_not_none(forecast.slots[0].maxDurationAdjustment) + + self.step("11") + if has_pfr: + # we include nominalPower + slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( + slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment, + nominalPower=forecast.slots[0].minPowerAdjustment)] + else: + # SFR we don't provide nominalPower + slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( + slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] + await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) + + self.step("12") + sub_handler.reset() + await self.send_cancel_request_command() + + self.step("13") + wait = 5 # We expect a change to the forecast attribute after the cancel, Wait 5 seconds - allow time for the report to come in + accumulate_reports(wait) + + self.step("13a") + count = sub_handler.attribute_report_counts[Clusters.DeviceEnergyManagement.Attributes.Forecast] + logging.info(f"Received {count} Forecast updates in {wait} seconds") + asserts.assert_greater_equal(count, 1, "Expected >= 1 Forecast updates after a cancelled operation") + + self.step("14") + await self.send_test_event_trigger_forecast_adjustment_clear() + + self.step("15") + if not has_pa: + self.skip_step("16") + self.skip_step("16b") + self.skip_step("17") + self.skip_step("18") + self.skip_step("18a") + self.skip_step("19") + self.skip_step("20") + self.skip_step("20a") + self.skip_step("21") + else: + + self.step("16") + await self.send_test_event_trigger_power_adjustment() + + self.step("16b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + logging.info(powerAdjustCapabilityStruct) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) + + # we should expect powerAdjustCapabilityStruct to have multiple entries with different max powers, min powers, max and min durations + min_power = sys.maxsize + max_power = 0 + + for entry in powerAdjustCapabilityStruct.powerAdjustCapability: + min_power = min(min_power, entry.minPower) + max_power = max(max_power, entry.maxPower) + + result = f"min_power {min_power} max_power {max_power}" + logging.info(result) + + self.step("17") + sub_handler.reset() + await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, + duration=20, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) + + self.step("18") + wait = 12 # Wait 12 seconds - the spec says we should only get reports every 10s at most, unless a command changes it + accumulate_reports(wait) + + self.step("18a") + count = sub_handler.attribute_report_counts[Clusters.DeviceEnergyManagement.Attributes.PowerAdjustmentCapability] + logging.info(f"Received {count} PowerAdjustmentCapability updates in {wait} seconds") + asserts.assert_less_equal(count, 2, f"Expected <= 2 PowerAdjustmentCapability updates in {wait} seconds") + + self.step("19") + sub_handler.reset() + await self.send_cancel_power_adjustment_command() + + self.step("20") + wait = 5 # We expect a change to the forecast attribute after the cancel, Wait 5 seconds - allow time for the report to come in + accumulate_reports(wait) + + self.step("20a") + count = sub_handler.attribute_report_counts[Clusters.DeviceEnergyManagement.Attributes.PowerAdjustmentCapability] + logging.info(f"Received {count} PowerAdjustmentCapability updates in {wait} seconds") + asserts.assert_greater_equal(count, 1, "Expected >= 1 PowerAdjustmentCapability updates after a cancelled operation") + + self.step("21") + await self.send_test_event_trigger_power_adjustment_clear() + + self.step("22") + await sub_handler.cancel() + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_DEM_2_2.py b/src/python_testing/TC_DEM_2_2.py index ae4f370ff741e3..3175508d056cb5 100644 --- a/src/python_testing/TC_DEM_2_2.py +++ b/src/python_testing/TC_DEM_2_2.py @@ -61,86 +61,88 @@ def pics_TC_DEM_2_2(self): def steps_TC_DEM_2_2(self) -> list[TestStep]: """Execute the test steps.""" steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads PowerAdjustmentCapability attribute.", + 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. Verify PowerAdjustment is supported."), + TestStep("3", "Set up a subscription to all DeviceEnergyManagement cluster events"), + TestStep("4", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster", + "Value has to be 1 (True)"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("5a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("5b", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=NoAdjustment. Note value for later. Determine the OverallMaxPower and OverallMaxDuration as the largest MaxPower and MaxDuration of the PowerAdjustStructs returned, and similarly the OverallMinPower and OverallMinDuration as the smallest of the MinPower and MinDuration values."), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and Event DEM.S.E00(PowerAdjustStart) sent"), - TestStep("4a", "TH reads ESAState attribute.", - "Verify value is 0x04 (PowerAdjustActive)"), - TestStep("4b", "TH reads PowerAdjustmentCapability attribute.", + TestStep("5c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("6", "TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("6a", "TH reads from the DUT the ESAState", + "Value has to be 0x04 (PowerAdjustActive)"), + TestStep("6b", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=LocalOptimizationAdjustment."), - TestStep("5", "TH sends CancelPowerAdjustRequest.", - "Verify DUT responds with status SUCCESS(0x00) and Event DEM.S.E01(PowerAdjustEnd) sent with Cause=Cancelled"), - TestStep("5a", "TH reads PowerAdjustmentCapability attribute.", + TestStep("7", "TH sends command CancelPowerAdjustRequest", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E01(PowerAdjustEnd) sent with Cause=Cancelled"), + TestStep("7a", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=NoAdjustment."), - TestStep("5b", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("6", "TH sends CancelPowerAdjustRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("7", "TH sends PowerAdjustRequest with Power=OverallMaxPower+1 Duration=OverallMinDuration Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("8", "TH sends PowerAdjustRequest with Power=OverallMinPower Duration=OverallMaxDuration+1 Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("9", "TH sends PowerAdjustRequest with Power=OverallMinPower-1 Duration=OverallMaxDuration Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("10", "TH sends PowerAdjustRequest with Power=OverallMaxPower Duration=OverallMinDuration-1 Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("11", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), - TestStep("11a", "TH reads PowerAdjustmentCapability attribute.", + TestStep("7b", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("8", "TH sends command CancelPowerAdjustRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("9", "TH sends command PowerAdjustRequest with Power=OverallMaxPower+1 Duration=OverallMinDuration Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("10", "TH sends command PowerAdjustRequest with Power=OverallMinPower Duration=OverallMaxDuration+1 Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("11", "TH sends command PowerAdjustRequest with Power=OverallMinPower-1 Duration=OverallMaxDuration Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12", "TH sends command PowerAdjustRequest with Power=OverallMaxPower Duration=OverallMinDuration-1 Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("13", "TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("13a", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=LocalOptimizationAdjustment."), - TestStep("12", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and no event sent"), - TestStep("12a", "TH reads ESAState attribute.", - "Verify value is 0x04 (PowerAdjustActive)"), - TestStep("12b", "TH reads PowerAdjustmentCapability attribute.", + TestStep("14", "TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and no event sent"), + TestStep("14a", "TH reads from the DUT the ESAState", + "Value has to be 0x04 (PowerAdjustActive)"), + TestStep("14b", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=GridOptimizationAdjustment."), - TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00) and no event sent"), - TestStep("13a", "TH reads ESAState attribute.", - "Verify value is 0x04 (PowerAdjustActive)"), - TestStep("13b", "TH reads OptOutState attribute.", - "Verify value is 0x02 (LocalOptOut)"), - TestStep("14", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E01(PowerAdjustEnd) sent with Cause=UserOptOut, Duration= approx time from step 11 to step 15, EnergyUse= a valid value"), - TestStep("15a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("15b", "TH reads OptOutState attribute.", - "Verify value is 0x03 (OptOut)"), - TestStep("15c", "TH reads PowerAdjustmentCapability attribute.", + TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00) and no event sent"), + TestStep("15a", "TH reads from the DUT the ESAState", + "Value has to be 0x04 (PowerAdjustActive)"), + TestStep("15b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (LocalOptOut)"), + TestStep("16", "TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("17", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00) and event DEM.S.E01(PowerAdjustEnd) sent with Cause=UserOptOut, Duration= approx time from step 11 to step 15, EnergyUse= a valid value"), + TestStep("17a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("17b", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("17c", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=NoAdjustment."), - TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("16a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("16b", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("17", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), - TestStep("17a", "TH reads ESAState attribute.", - "Verify value is 0x04 (PowerAdjustActive)"), - TestStep("17b", "TH reads PowerAdjustmentCapability attribute.", + TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("18a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("18b", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("19", "TH sends command PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("19a", "TH reads from the DUT the ESAState", + "Value has to be 0x04 (PowerAdjustActive)"), + TestStep("19b", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=LocalOptimizationAdjustment."), - TestStep("18", "Wait 10 seconds.", - "Event DEM.S.E01(PowerAdjustEnd) sent with Cause=NormalCompletion, Duration=10s, EnergyUse= a valid value"), - TestStep("18a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("18b", "TH reads PowerAdjustmentCapability attribute.", + TestStep("20", "Wait 10 seconds", + "Event DEM.S.E01(PowerAdjustEnd) sent with Cause=NormalCompletion, Duration in the range 10-12s, EnergyUse= a valid value"), + TestStep("20a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("20b", "TH reads from the DUT the PowerAdjustmentCapability", "Value has to include Cause=NoAdjustment."), - TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("21", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -155,22 +157,26 @@ async def test_TC_DEM_2_2(self): self.step("1") # Commission DUT - already done + self.step("2") + await self.validate_feature_map([Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerAdjustment], []) + + self.step("3") # Subscribe to Events and when they are sent push them to a queue for checking later events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) await events_callback.start(self.default_controller, self.dut_node_id, self.matter_test_config.endpoint) - self.step("2") + self.step("4") await self.check_test_event_triggers_enabled() - self.step("3") + self.step("5") await self.send_test_event_trigger_power_adjustment() - self.step("3a") + self.step("5a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("5b") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) logging.info(powerAdjustCapabilityStruct) @@ -192,66 +198,66 @@ async def test_TC_DEM_2_2(self): result = f"min_power {min_power} max_power {max_power} min_duration {min_duration} max_duration {max_duration}" logging.info(result) - self.step("3c") + self.step("5c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("6") await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) - self.step("4a") + self.step("6a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) - self.step("4b") + self.step("6b") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) - self.step("5") + self.step("7") await self.send_cancel_power_adjustment_command() event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kCancelled) - self.step("5a") + self.step("7a") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) - self.step("5b") + self.step("7b") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("6") + self.step("8") await self.send_cancel_power_adjustment_command(expected_status=Status.InvalidInState) - self.step("7") + self.step("9") await self.send_power_adjustment_command(power=max_power + 1, duration=min_duration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("8") + self.step("10") await self.send_power_adjustment_command(power=min_power, duration=max_duration + 1, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("9") + self.step("11") await self.send_power_adjustment_command(power=min_power - 1, duration=max_duration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("10") + self.step("12") await self.send_power_adjustment_command(power=max_power, duration=min_duration - 1, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("11") + self.step("13") start = datetime.datetime.now() await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].minPower, duration=min_duration, @@ -259,12 +265,12 @@ async def test_TC_DEM_2_2(self): event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) - self.step("11a") + self.step("13a") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) - self.step("12") + self.step("14") await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization) @@ -272,30 +278,30 @@ async def test_TC_DEM_2_2(self): # Wait 5 seconds for an event not to be reported events_callback.wait_for_event_expect_no_report(5) - self.step("12a") + self.step("14a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) - self.step("12b") + self.step("14b") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kGridOptimizationAdjustment) - self.step("13") + self.step("15") await self.send_test_event_trigger_user_opt_out_local() - self.step("13a") + self.step("15a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) - self.step("13b") + self.step("15b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("14") + self.step("16") await self.send_power_adjustment_command(power=max_power, duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxDuration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("15") + self.step("17") await self.send_test_event_trigger_user_opt_out_grid() event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kUserOptOut) @@ -305,58 +311,60 @@ async def test_TC_DEM_2_2(self): asserts.assert_less_equal(abs(elapsed.seconds - event_data.duration), 3) asserts.assert_greater_equal(event_data.energyUse, 0) - self.step("15a") + self.step("17a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("15b") + self.step("17b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("15c") + self.step("17c") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) - self.step("16") + self.step("18") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("16a") + self.step("18a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("16b") + self.step("18b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("17") + self.step("19") await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Success) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) - self.step("17a") + self.step("19a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) - self.step("17b") + self.step("19b") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) - self.step("18") + self.step("20") time.sleep(10) + # Allow a little tolerance checking the duration returned in the event as CI tests can run "slower" event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) - asserts.assert_equal(event_data.duration, 10) + asserts.assert_greater_equal(event_data.duration, 10) + asserts.assert_less_equal(event_data.duration, 12) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kNormalCompletion) asserts.assert_greater(event_data.energyUse, 0) - self.step("18a") + self.step("20a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("18b") + self.step("20b") powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") asserts.assert_equal(powerAdjustCapabilityStruct.cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) - self.step("19") + self.step("21") await self.send_test_event_trigger_power_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_3.py b/src/python_testing/TC_DEM_2_3.py index 8174c7bee5d273..d462c390596449 100644 --- a/src/python_testing/TC_DEM_2_3.py +++ b/src/python_testing/TC_DEM_2_3.py @@ -22,7 +22,7 @@ # test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} # 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 0x7a --application evse +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0xa --application evse # 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 === @@ -31,7 +31,7 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue from chip.interaction_model import Status -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -54,78 +54,79 @@ def pics_TC_DEM_2_3(self): def steps_TC_DEM_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 that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Start Time Adjustment Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast attribute.", + 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. Verify StartTimeAdjustment feature is supported on the cluster. Verify PowerForecastReporting or StateForecastReporting feature is supported on the cluster."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Start Time Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include EarliestStartTime<=StartTime, LatestEndTime>=EndTime, and ForecastUpdateReason=Internal Optimization"), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("4a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("4b", "TH reads OptOutState attribute.", - "Verify value is 0x01 (LocalOptOut)"), - TestStep("5", "TH sends StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime from Forecast, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("5a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("5b", "TH reads Forecast attribute.", + TestStep("4c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("5a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("5b", "TH reads from the DUT the OptOutState", + "Value has to be 0x01 (LocalOptOut)"), + TestStep("6", "TH sends command StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime from Forecast, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("6a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("6b", "TH reads from the DUT the Forecast", "Value has to be unchanged from step 3b"), - TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("6a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("6b", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("7", "TH sends StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime from Forecast, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("7a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("7b", "TH reads Forecast attribute.", + TestStep("7", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("7a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("7b", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("8", "TH sends command StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime from Forecast, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("8a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("8b", "TH reads from the DUT the Forecast", "Value has to include EarliestStartTime=StartTime, LatestEndTime>=EndTime, and ForecastUpdateReason=Local Optimization"), - TestStep("8", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("8a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("8b", "TH reads OptOutState attribute.", - "Verify value is 0x01 (LocalOptOut)"), - TestStep("8c", "TH reads Forecast attribute.", + TestStep("9", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("9a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("9b", "TH reads from the DUT the OptOutState", + "Value has to be 0x01 (LocalOptOut)"), + TestStep("9c", "TH reads from the DUT the Forecast", "Value has to include EarliestStartTime<=StartTime, LatestEndTime>=EndTime, and ForecastUpdateReason=Internal Optimization"), - TestStep("9", "TH sends StartTimeAdjustRequest with RequestedStartTime=StartTime+(LatestEndTime-EndTime) from Forecast, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("9a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("9b", "TH reads Forecast attribute.", + TestStep("10", "TH sends command StartTimeAdjustRequest with RequestedStartTime=StartTime+(LatestEndTime-EndTime) from Forecast, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("10a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("10b", "TH reads from the DUT the Forecast", "Value has to include EarliestStartTime<=StartTime, LatestEndTime=EndTime, and ForecastUpdateReason=Grid Optimization"), - TestStep("10", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("10a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("10b", "TH reads Forecast attribute.", + TestStep("11", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("11a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("11b", "TH reads from the DUT the Forecast", "Value has to include EarliestStartTime<=StartTime, LatestEndTime>=EndTime, and ForecastUpdateReason=Internal Optimization"), - TestStep("11", "TH sends StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime-1 from Forecast, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("11a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("11b", "TH reads Forecast attribute.", + TestStep("12", "TH sends command StartTimeAdjustRequest with RequestedStartTime=EarliestStartTime-1 from Forecast, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("12b", "TH reads from the DUT the Forecast", "Value has to include StartTime and EndTime unchanged from step 10b"), - TestStep("12", "TH sends StartTimeAdjustRequest with RequestedStartTime=StartTime+(LatestEndTime-EndTime)+1 from Forecast, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("12a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("12b", "TH reads Forecast attribute.", + TestStep("13", "TH sends command StartTimeAdjustRequest with RequestedStartTime=StartTime+(LatestEndTime-EndTime)+1 from Forecast, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("13a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("13b", "TH reads from the DUT the Forecast", "Value has to include StartTime and EndTime unchanged from step 10b"), - TestStep("13", "TH sends CancelRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Start Time Adjustment Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("14", "TH sends command CancelRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Start Time Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -138,22 +139,20 @@ async def test_TC_DEM_2_3(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_feature_map([Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStartTimeAdjustment], []) + await self.validate_pfr_or_sfr_in_feature_map() self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_start_time_adjustment() - self.step("3a") + self.step("4a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("4b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_not_equal(forecast, NullValue) @@ -166,48 +165,48 @@ async def test_TC_DEM_2_3(self): self.print_forecast(forecast) - self.step("3c") + self.step("4c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("5") await self.send_test_event_trigger_user_opt_out_local() - self.step("4a") + self.step("5a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("4b") + self.step("5b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("5") + self.step("6") await self.send_start_time_adjust_request_command(requestedStartTime=forecast.earliestStartTime, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("5a") + self.step("6a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("5b") + self.step("6b") forecast2 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast, forecast2, f"Expected same forcast {forecast} to be == {forecast2}") - self.step("6") + self.step("7") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("6a") + self.step("7a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("6b") + self.step("7b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("7") + self.step("8") await self.send_start_time_adjust_request_command(requestedStartTime=forecast.earliestStartTime, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) - self.step("7a") + self.step("8a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("7b") + self.step("8b") forecast3 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast3.earliestStartTime, forecast3.startTime, f"Expected earliestStartTime {forecast3.earliestStartTime} to be == startTime {forecast3.startTime}") @@ -216,16 +215,16 @@ async def test_TC_DEM_2_3(self): asserts.assert_equal(forecast3.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization, f"Expected forecastUpdateReason {forecast3.forecastUpdateReason} to be == LocalOptimization {Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization}") - self.step("8") + self.step("9") await self.send_test_event_trigger_user_opt_out_local() - self.step("8a") + self.step("9a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("8b") + self.step("9b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("8c") + self.step("9c") forecast4 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_less_equal(forecast4.earliestStartTime, forecast4.startTime, f"Expected earliestStartTime {forecast4.earliestStartTime} to be <= startTime {forecast4.startTime}") @@ -234,14 +233,14 @@ async def test_TC_DEM_2_3(self): asserts.assert_equal(forecast4.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization, f"Expected forecastUpdateReason {forecast4.forecastUpdateReason} to be == InternalOptimization {Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization}") - self.step("9") + self.step("10") await self.send_start_time_adjust_request_command(requestedStartTime=forecast4.startTime+forecast4.latestEndTime - forecast4.endTime, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization) - self.step("9a") + self.step("10a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("9b") + self.step("10b") forecast5 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_less_equal(forecast5.earliestStartTime, forecast5.startTime, f"Expected earliestStartTime {forecast5.earliestStartTime} to be <= startTime {forecast5.startTime}") @@ -250,13 +249,13 @@ async def test_TC_DEM_2_3(self): asserts.assert_equal(forecast5.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization, f"Expected forecastUpdateReason {forecast5.forecastUpdateReason} to be == GridOptimization {Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization}") - self.step("10") + self.step("11") await self.send_cancel_request_command() - self.step("10a") + self.step("11a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("10b") + self.step("11b") forecast6 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_less_equal(forecast6.earliestStartTime, forecast6.startTime, f"Expected earliestStartTime {forecast6.earliestStartTime} to be <= startTime {forecast6.startTime}") @@ -265,38 +264,38 @@ async def test_TC_DEM_2_3(self): asserts.assert_equal(forecast6.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization, f"Expected forecastUpdateReason {forecast6.forecastUpdateReason} to be == InternalOptimization {Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization}") - self.step("11") + self.step("12") await self.send_start_time_adjust_request_command(requestedStartTime=forecast6.earliestStartTime - 1, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("11a") + self.step("12a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("11b") + self.step("12b") forecast7 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast6.startTime, forecast7.startTime, f"Expected old startTime {forecast6.startTime} to be == startTime {forecast7.startTime}") asserts.assert_equal(forecast6.endTime, forecast7.endTime, f"Expected old endTime {forecast6.endTime} to be == endTime {forecast7.endTime}") - self.step("12") + self.step("13") await self.send_start_time_adjust_request_command(requestedStartTime=forecast7.startTime+(forecast7.latestEndTime-forecast7.endTime)+1, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("12a") + self.step("13a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("12b") + self.step("13b") forecast8 = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast7.startTime, forecast8.startTime, f"Expected old startTime {forecast7.startTime} to be == startTime {forecast8.startTime}") asserts.assert_equal(forecast7.endTime, forecast8.endTime, f"Expected old endTime {forecast7.endTime} to be == endTime {forecast8.endTime}") - self.step("13") + self.step("14") await self.send_cancel_request_command(expected_status=Status.InvalidInState) - self.step("14") + self.step("15") await self.send_test_event_trigger_start_time_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_4.py b/src/python_testing/TC_DEM_2_4.py index 6041dcf9e0cc76..734712099e8798 100644 --- a/src/python_testing/TC_DEM_2_4.py +++ b/src/python_testing/TC_DEM_2_4.py @@ -22,7 +22,7 @@ # test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} # 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 0x7a --application evse +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x12 --application evse # 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 === @@ -55,98 +55,100 @@ def pics_TC_DEM_2_4(self): def steps_TC_DEM_2_4(self) -> list[TestStep]: steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast.", - "Value has to include IsPausable=True, slot[0].SlotIsPausable=True, slot[0].MinPauseDuration>1, slot[0].MaxPauseDuration>1, slot[1].SlotIsPausable=False, ActiveSlotNumber=0, and ForecastUpdateReason=Internal Optimization"), - TestStep("3c", "TH reads OptOutState.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration-1, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("4a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("5", "TH sends PauseRequest with Duration=Forecast.slots[0].MaxPauseDuration+1, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("5a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("6", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("6a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("6b", "TH reads OptOutState.", - "Verify value is 0x02 (GridOptOut)"), - TestStep("7", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("7a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("8", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E02(Paused) sent"), - TestStep("8a", "TH reads ESAState.", - "Verify value is 0x05 (Paused)"), - TestStep("9", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E03(Resumed) sent with Cause=3 (UserOptOut)"), - TestStep("9a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("9b", "TH reads OptOutState.", - "Verify value is 0x03 (OptOut)"), - TestStep("9c", "TH reads Forecast.", - "Value has to include ForecastUpdateReason=Internal Optimization"), - TestStep("10", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("10a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("10b", "TH reads OptOutState.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("11", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E02(Paused) sent"), - TestStep("11a", "TH reads ESAState.", - "Verify value is 0x05 (Paused)"), - TestStep("11b", "TH reads Forecast.", + 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. Verify Pausable feature is supported on the cluster. Verify PowerForecastReporting or StateForecastReporting feature is supported on the cluster."), + TestStep("3", "Set up a subscription to all DeviceEnergyManagement cluster events"), + TestStep("4", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster", + "Value has to be 1 (True)"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("5a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("5b", "TH reads from the DUT the Forecast", + "Value has to include IsPausable=True, slots[0].SlotIsPausable=True, slots[0].MinPauseDuration>1, slots[0].MaxPauseDuration>1, slots[1].SlotIsPausable=False, ActiveSlotNumber=0, and ForecastUpdateReason=Internal Optimization"), + TestStep("5c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("6", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration-1, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("6a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("7", "TH sends command PauseRequest with Duration=Forecast.slots[0].MaxPauseDuration+1, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("7a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("8", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("8a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("8b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (GridOptOut)"), + TestStep("9", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("9a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("10", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E02(Paused) sent"), + TestStep("10a", "TH reads from the DUT the ESAState", + "Value has to be 0x05 (Paused)"), + TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E03(Resumed) sent with Cause=3 (UserOptOut)"), + TestStep("11a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("11b", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("11c", "TH reads from the DUT the Forecast", + "Value has to include ForecastUpdateReason=Internal Optimization"), + TestStep("12", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("12a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("12b", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("13", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E02(Paused) sent"), + TestStep("13a", "TH reads from the DUT the ESAState", + "Value has to be 0x05 (Paused)"), + TestStep("13b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=Local Optimization"), - TestStep("12", "TH sends ResumeRequest.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E03(Resumed) sent with Cause=4 (Cancelled)"), - TestStep("12a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("12b", "TH reads Forecast.", - "Value has to include IsPausable=True, slots[0].SlotIsPausable=True, slots[0].MinPauseDuration>1, slots[0].MaxPauseDuration>1, slots[1].SlotIsPausable=False, ActiveSlotNumber=0, ForecastUpdateReason=Internal Optimization"), - TestStep("13", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E02(Paused) sent"), - TestStep("13a", "TH reads ESAState.", - "Verify value is 0x05 (Paused)"), - TestStep("13b", "TH reads Forecast.", + TestStep("14", "TH sends command ResumeRequest", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E03(Resumed) sent with Cause=4 (Cancelled)"), + TestStep("14a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("14b", "TH reads from the DUT the Forecast", + "Value has to include IsPausable=True, slots[0].SlotIsPausable=True, slots[0].MinPauseDuration>1, slots[0].MaxPauseDuration>1, slots[1].SlotIsPausable=False, ActiveSlotNumber=0, ForecastUpdateReason=InternalOptimization"), + TestStep("15", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E02(Paused) sent"), + TestStep("15a", "TH reads from the DUT the ESAState", + "Value has to be 0x05 (Paused)"), + TestStep("15b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=Local Optimization"), - TestStep("14", "TH sends ResumeRequest.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E03(Resumed) sent with Cause=4 (Cancelled)"), - TestStep("14a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("15", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E02(Paused) sent"), - TestStep("15a", "TH reads ESAState.", - "Verify value is 0x05 (Paused)"), - TestStep("16", "Wait for minPauseDuration.", + TestStep("16", "TH sends command ResumeRequest", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E03(Resumed) sent with Cause=4 (Cancelled)"), + TestStep("16a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("17", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00) and Event DEM.S.E02(Paused) sent"), + TestStep("17a", "TH reads from the DUT the ESAState", + "Value has to be 0x05 (Paused)"), + TestStep("18", "Wait for minPauseDuration.", "Event DEM.S.E03(Resumed) sent with Cause=0 (NormalCompletion)"), - TestStep("16a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("17", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event Next Slot.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("17a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("17b", "TH reads Forecast.", + TestStep("18a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event Next Slot", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("19a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("19b", "TH reads from the DUT the Forecast", "Value has to include ActiveSlotNumber=1"), - TestStep("18", "TH sends PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("18a", "TH reads ESAState.", - "Verify value is 0x01 (Online)"), - TestStep("19", "TH sends ResumeRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("20", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event Clear.", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("20", "TH sends command PauseRequest with Duration=Forecast.slots[0].MinPauseDuration, Cause=LocalOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("20a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("21", "TH sends command ResumeRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("22", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Pausable Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -159,22 +161,27 @@ async def test_TC_DEM_2_4(self): self.step("1") # Commission DUT - already done + self.step("2") + await self.validate_feature_map([Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPausable], []) + await self.validate_pfr_or_sfr_in_feature_map() + + self.step("3") # Subscribe to Events and when they are sent push them to a queue for checking later events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) await events_callback.start(self.default_controller, self.dut_node_id, self.matter_test_config.endpoint) - self.step("2") + self.step("4") await self.check_test_event_triggers_enabled() - self.step("3") + self.step("5") await self.send_test_event_trigger_pausable() - self.step("3a") + self.step("5a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("5b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_not_equal(forecast, NullValue) @@ -193,100 +200,100 @@ async def test_TC_DEM_2_4(self): f"Expected forecast forecastUpdateReason {forecast.forecastUpdateReason} to be == Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization") self.print_forecast(forecast) - self.step("3c") + self.step("5c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("6") await self.send_pause_request_command(forecast.slots[0].minPauseDuration - 1, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("4a") + self.step("6a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("5") + self.step("7") await self.send_pause_request_command(forecast.slots[0].maxPauseDuration + 1, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("5a") + self.step("7a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("6") + self.step("8") await self.send_test_event_trigger_user_opt_out_grid() - self.step("6a") + self.step("8a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("6b") + self.step("8b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kGridOptOut) - self.step("7") + self.step("9") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("7a") + self.step("9a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("8") + self.step("10") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Paused) - self.step("8a") + self.step("10a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPaused) - self.step("9") + self.step("11") await self.send_test_event_trigger_user_opt_out_local() event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Resumed) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kUserOptOut) - self.step("9a") + self.step("11a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("9b") + self.step("11b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("9c") + self.step("11c") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_not_equal(forecast, NullValue) asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("10") + self.step("12") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("10a") + self.step("12a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("10b") + self.step("12b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("11") + self.step("13") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Paused) - self.step("11a") + self.step("13a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPaused) - self.step("11b") + self.step("13b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("12") + self.step("14") await self.send_resume_request_command() event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Resumed) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kCancelled) - self.step("12a") + self.step("14a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("12b") + self.step("14b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.isPausable, True) asserts.assert_greater(forecast.slots[0].minPauseDuration, 1) @@ -297,66 +304,66 @@ async def test_TC_DEM_2_4(self): asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("13") + self.step("15") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Paused) - self.step("13a") + self.step("15a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPaused) - self.step("13b") + self.step("15b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("14") + self.step("16") await self.send_resume_request_command() event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Resumed) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kCancelled) - self.step("14a") + self.step("16a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("15") + self.step("17") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Paused) - self.step("15a") + self.step("17a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPaused) - self.step("16") + self.step("18") logging.info(f"Sleeping for forecast.slots[0].minPauseDuration {forecast.slots[0].minPauseDuration}s") time.sleep(forecast.slots[0].minPauseDuration) event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.Resumed) asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kNormalCompletion) - self.step("16a") + self.step("18a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("17") + self.step("19") await self.send_test_event_trigger_pausable_next_slot() - self.step("17a") + self.step("19a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("17b") + self.step("19b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.activeSlotNumber, 1) - self.step("18") + self.step("20") await self.send_pause_request_command(forecast.slots[0].minPauseDuration, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Failure) - self.step("18a") + self.step("20a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("19") + self.step("21") await self.send_resume_request_command(expected_status=Status.InvalidInState) - self.step("20") + self.step("22") await self.send_test_event_trigger_user_opt_out_clear_all() diff --git a/src/python_testing/TC_DEM_2_5.py b/src/python_testing/TC_DEM_2_5.py index a822e7ff8f5c8e..38bac00f32cfdf 100644 --- a/src/python_testing/TC_DEM_2_5.py +++ b/src/python_testing/TC_DEM_2_5.py @@ -23,7 +23,7 @@ # test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} # 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 0x7a --application evse +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x22 --application evse # 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 === @@ -34,7 +34,7 @@ import chip.clusters as Clusters from chip.interaction_model import Status -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -59,80 +59,83 @@ def pics_TC_DEM_2_5(self): def steps_TC_DEM_2_5(self) -> list[TestStep]: """Execute the test steps.""" steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast attribute.", + 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. Verify ForecastAdjustment feature is supported on the cluster. Verify PowerForecastReporting feature is supported on the cluster. Verify StateForecastReporting feature is not supported on the cluster."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include slots[0].MinPowerAdjustment, slots[0].MaxPowerAdjustment, slots[0].MinDurationAdjustment, slots[0].MaxDurationAdjustment"), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID+1, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("5", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=4, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("6", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment-1, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("7", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment+1, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("8", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment+1}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("9", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment-1}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("10", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, SlotAdjustments[1].{SlotIndex=4, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("11a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("11b", "TH reads OptOutState attribute.", - "Verify value is 0x02 (LocalOptOut)"), - TestStep("12", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("13", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("13a", "TH reads Forecast attribute.", + TestStep("4c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("5", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("6", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID+1, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("7", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=len(Forecast.Slots), NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("8", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment-1, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("9", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment+1, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("10", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment+1}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("11", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment-1}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, SlotAdjustments[1].{SlotIndex=4, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("13a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("13b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (LocalOptOut)"), + TestStep("14", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("15", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("15a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("14", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("14a", "TH reads Forecast attribute.", + TestStep("16", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("16a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("15", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("15a", "TH reads Forecast attribute.", + TestStep("17", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("17a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("16a", "TH reads OptOutState attribute.", - "Verify value is 0x03 (OptOut)"), - TestStep("16b", "TH reads Forecast attribute.", + TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("18a", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("18b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=Internal Optimization"), - TestStep("17", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("18a", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("19", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("19a", "TH reads Forecast attribute.", + TestStep("19", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MinPowerAdjustment, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("20", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("20a", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("21", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("21a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=LocalOptimization"), - TestStep("20", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("20a", "TH reads Forecast attribute.", + TestStep("22", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("22a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("21", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Next Slot", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("22", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("23", "TH sends CancelRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("24", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("23", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Next Slot", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("24", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, NominalPower=Forecast.Slots[0].MaxPowerAdjustment, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("25", "TH sends command CancelRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("26", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -144,22 +147,21 @@ async def test_TC_DEM_2_5(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_feature_map(must_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kForecastAdjustment, + Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting], + must_not_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting]) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_forecast_adjustment() - self.step("3a") + self.step("4a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("4b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_is_not_none(forecast.slots[0].minPowerAdjustment) @@ -167,138 +169,143 @@ async def test_TC_DEM_2_5(self): asserts.assert_is_not_none(forecast.slots[0].minDurationAdjustment) asserts.assert_is_not_none(forecast.slots[0].maxDurationAdjustment) - self.step("3c") + self.step("4c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("5") + slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( + slotIndex=0, duration=forecast.slots[0].minDurationAdjustment)] + await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) + + self.step("6") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID + 1, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("5") + self.step("7") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( - slotIndex=4, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] + slotIndex=len(forecast.slots), nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("6") + self.step("8") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment - 1, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("7") + self.step("9") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].maxPowerAdjustment + 1, duration=forecast.slots[0].minDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("8") + self.step("10") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment + 1)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("9") + self.step("11") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].maxPowerAdjustment, duration=forecast.slots[0].minDurationAdjustment - 1)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("10") + self.step("12") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct(slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment), Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct(slotIndex=4, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("11") + self.step("13") await self.send_test_event_trigger_user_opt_out_local() - self.step("11a") + self.step("13a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("11b") + self.step("13b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("12") + self.step("14") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("13") + self.step("15") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("13a") + self.step("15a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("14") + self.step("16") await self.send_cancel_request_command() - self.step("14a") + self.step("16a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("15") + self.step("17") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("15a") + self.step("17a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("16") + self.step("18") await self.send_test_event_trigger_user_opt_out_grid() - self.step("16a") + self.step("18a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("16b") + self.step("18b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("17") + self.step("19") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("18") + self.step("20") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("18a") + self.step("20a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("19") + self.step("21") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].minDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Success) - self.step("19a") + self.step("21a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("20") + self.step("22") await self.send_cancel_request_command() - self.step("20a") + self.step("22a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("21") + self.step("23") await self.send_test_event_trigger_forecast_adjustment_next_slot() - self.step("22") + self.step("24") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, nominalPower=forecast.slots[0].minPowerAdjustment, duration=forecast.slots[0].minDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("23") + self.step("25") await self.send_cancel_request_command(expected_status=Status.InvalidInState) - self.step("24") + self.step("26") await self.send_test_event_trigger_forecast_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_6.py b/src/python_testing/TC_DEM_2_6.py index 12bf060e37a471..c05a80c6c3909a 100644 --- a/src/python_testing/TC_DEM_2_6.py +++ b/src/python_testing/TC_DEM_2_6.py @@ -34,7 +34,7 @@ import chip.clusters as Clusters from chip.interaction_model import Status -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -59,76 +59,77 @@ def pics_TC_DEM_2_6(self): def steps_TC_DEM_2_6(self) -> list[TestStep]: """Execute the test steps.""" steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast attribute.", + 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. Verify ForecastAdjustment feature is supported on the cluster. Verify StateForecastReporting feature is supported on the cluster. Verify PowerForecastReporting feature is not supported on the cluster."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include slots[0].MinDurationAdjustment, slots[0].MaxDurationAdjustment"), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID+1, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("5", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=4, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("6", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment+1}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("7", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment-1}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("8", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, SlotAdjustments[1].{SlotIndex=4, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status FAILURE(0x01)"), - TestStep("9", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("9a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("9b", "TH reads OptOutState attribute.", - "Verify value is 0x02 (LocalOptOut)"), - TestStep("10", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("11", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("11a", "TH reads Forecast attribute.", + TestStep("4c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("5", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID+1, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("6", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=4, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("7", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment+1}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("8", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment-1}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("9", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, SlotAdjustments[1].{SlotIndex=4, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status FAILURE(0x01)"), + TestStep("10", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("10a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("10b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (LocalOptOut)"), + TestStep("11", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("12a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("12", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("12a", "TH reads Forecast attribute.", + TestStep("13", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("13a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("13", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("13a", "TH reads Forecast attribute.", + TestStep("14", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("14a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("14a", "TH reads OptOutState attribute.", - "Verify value is 0x03 (OptOut)"), - TestStep("14b", "TH reads Forecast attribute.", + TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("15a", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("15b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=Internal Optimization"), - TestStep("15", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("16a", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("17", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("17a", "TH reads Forecast attribute.", + TestStep("16", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MaxDurationAdjustment}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("17", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("17a", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("18", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("18a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=LocalOptimization"), - TestStep("18", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("18a", "TH reads Forecast attribute.", + TestStep("19", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("19a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Next Slot", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("20", "TH sends ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("21", "TH sends CancelRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("22", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("20", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Next Slot", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("21", "TH sends command ModifyForecastRequest with ForecastID=Forecast.ForecastID, SlotAdjustments[0].{SlotIndex=0, Duration=Forecast.Slots[0].MinDurationAdjustment}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("22", "TH sends command CancelRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("23", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -140,149 +141,148 @@ async def test_TC_DEM_2_6(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_feature_map(must_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kForecastAdjustment, + Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting], + must_not_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting]) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_forecast_adjustment() - self.step("3a") + self.step("4a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("4b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_is_not_none(forecast.slots[0].minDurationAdjustment) asserts.assert_is_not_none(forecast.slots[0].maxDurationAdjustment) - self.step("3c") + self.step("4c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("5") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID + 1, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("5") + self.step("6") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=4, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("6") + self.step("7") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment + 1)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("7") + self.step("8") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].minDurationAdjustment - 1)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("8") + self.step("9") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct(slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment), Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct(slotIndex=4, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Failure) - self.step("9") + self.step("10") await self.send_test_event_trigger_user_opt_out_local() - self.step("9a") + self.step("10a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("9b") + self.step("10b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("10") + self.step("11") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("11") + self.step("12") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("11a") + self.step("12a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") logging.info(forecast) asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("12") + self.step("13") await self.send_cancel_request_command() - self.step("12a") + self.step("13a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("13") + self.step("14") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("13a") + self.step("14a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("14") + self.step("15") await self.send_test_event_trigger_user_opt_out_grid() - self.step("14a") + self.step("15a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("14b") + self.step("15b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("15") + self.step("16") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].maxDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("16") + self.step("17") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("16a") + self.step("17a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("17") + self.step("18") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].minDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Success) - self.step("17a") + self.step("18a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("18") + self.step("19") await self.send_cancel_request_command() - self.step("18a") + self.step("19a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("19") + self.step("20") await self.send_test_event_trigger_forecast_adjustment_next_slot() - self.step("20") + self.step("21") slotAdjustments = [Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct( slotIndex=0, duration=forecast.slots[0].minDurationAdjustment)] await self.send_modify_forecast_request_command(forecast.forecastID, slotAdjustments, Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("21") + self.step("22") await self.send_cancel_request_command(expected_status=Status.InvalidInState) - self.step("22") + self.step("23") await self.send_test_event_trigger_forecast_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_7.py b/src/python_testing/TC_DEM_2_7.py index 46f037731f0cbd..b45643868a6e71 100644 --- a/src/python_testing/TC_DEM_2_7.py +++ b/src/python_testing/TC_DEM_2_7.py @@ -34,7 +34,7 @@ import chip.clusters as Clusters from chip.interaction_model import Status -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -59,84 +59,85 @@ def pics_TC_DEM_2_7(self): def steps_TC_DEM_2_7(self) -> list[TestStep]: """Execute the test steps.""" 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast attribute.", + 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. Verify ConstraintBasedAdjustment feature is supported on the cluster. Verify PowerForecastReporting feature is supported on the cluster. Verify StateForecastReporting feature is not supported on the cluster."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include valid slots[0].NominalPower, slots[0].MinPower, slots[0].MaxPower, slots[0].NominalEnergy"), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()-10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("5", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+20, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+40, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("6", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+40, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("7", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+50, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("8", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+50, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("9", "TH reads AbsMaxPower attribute attribute.", + TestStep("4c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("5", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()-10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("6", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+20, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+40, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("7", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+40, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("8", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+50, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("9", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[1].{StartTime=now()+50, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, constraints[2].{StartTime=now()+30, Duration=20, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("10", "TH reads from the DUT the AbsMaxPower attribute.", "Save the value"), - TestStep("9a", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=AbsMaxPower+1, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("10", "TH reads AbsMinPower attribute attribute.", + TestStep("10a", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=AbsMaxPower+1, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("11", "TH reads from the DUT the AbsMinPower attribute.", "Save the value"), - TestStep("10a", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=AbsMinPower-1, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("11", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower}, Cause=LocalOptimization.", - "Verify DUT responds with status InvalidCommand"), - TestStep("12", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status InvalidCommand"), - TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("13a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("13b", "TH reads OptOutState attribute.", - "Verify value is 0x02 (LocalOptOut)"), - TestStep("14", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("15", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("15a", "TH reads Forecast attribute.", + TestStep("11a", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=AbsMinPower-1, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower}, Cause=LocalOptimization", + "Verify DUT responds w/ status INVALID_COMMAND(0x85)"), + TestStep("13", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status INVALID_COMMAND(0x85)"), + TestStep("14", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("14a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("14b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (LocalOptOut)"), + TestStep("15", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("16", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("16a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("16", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("16a", "TH reads Forecast attribute.", + TestStep("17", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("17a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("17", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("17a", "TH reads Forecast attribute.", + TestStep("18", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("18a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("18a", "TH reads OptOutState attribute.", - "Verify value is 0x03 (OptOut)"), - TestStep("18b", "TH reads Forecast attribute.", + TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("19a", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("19b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("19", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("20", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("20a", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("21", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("21a", "TH reads Forecast attribute.", + TestStep("20", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("21", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("21a", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("22", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, NominalPower=Forecast.Slots[0].NominalPower, MaximumEnergy=Forecast.Slots[0].NominalEnergy}, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("22a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=LocalOptimization"), - TestStep("22", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("22a", "TH reads Forecast attribute.", + TestStep("23", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("23a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("23", "TH sends CancelRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("24", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Adjustment Test Event Clear.", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("24", "TH sends command CancelRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("25", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -148,22 +149,21 @@ async def test_TC_DEM_2_7(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_feature_map(must_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kConstraintBasedAdjustment, + Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting], + must_not_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting]) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_constraint_based_adjustment() - self.step("3a") + self.step("4a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("4b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") logging.info(forecast) asserts.assert_greater(forecast.slots[0].nominalPower, 0) @@ -171,10 +171,10 @@ async def test_TC_DEM_2_7(self): asserts.assert_greater(forecast.slots[0].maxPower, 0) asserts.assert_greater(forecast.slots[0].nominalEnergy, 0) - self.step("3c") + self.step("4c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("5") # Matter UTC is time since 00:00:00 1/1/2000 now = self.get_current_utc_time_in_seconds() @@ -182,7 +182,7 @@ async def test_TC_DEM_2_7(self): nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("5") + self.step("6") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 10, duration=20, @@ -193,7 +193,7 @@ async def test_TC_DEM_2_7(self): nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("6") + self.step("7") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 10, duration=20, @@ -204,7 +204,7 @@ async def test_TC_DEM_2_7(self): nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("7") + self.step("8") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 30, duration=20, @@ -215,7 +215,7 @@ async def test_TC_DEM_2_7(self): nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("8") + self.step("9") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 10, duration=20, @@ -226,118 +226,118 @@ async def test_TC_DEM_2_7(self): nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("9") + self.step("10") absMaxPower = await self.read_dem_attribute_expect_success(attribute="AbsMaxPower") - self.step("9a") + self.step("10a") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=absMaxPower + 1, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("10") + self.step("11") absMinPower = await self.read_dem_attribute_expect_success(attribute="AbsMinPower") - self.step("10a") + self.step("11a") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=absMinPower - 1, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("11") + self.step("12") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.InvalidCommand) - self.step("12") + self.step("13") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.InvalidCommand) - self.step("13") + self.step("14") await self.send_test_event_trigger_user_opt_out_local() - self.step("13a") + self.step("14a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("13b") + self.step("14b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("14") + self.step("15") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("15") + self.step("16") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("15a") + self.step("16a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("16") + self.step("17") await self.send_cancel_request_command() - self.step("16a") + self.step("17a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("17") + self.step("18") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("17a") + self.step("18a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("18") + self.step("19") await self.send_test_event_trigger_user_opt_out_grid() - self.step("18a") + self.step("19a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("18b") + self.step("19b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("19") + self.step("20") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("20") + self.step("21") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("20a") + self.step("21a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("21") + self.step("22") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, nominalPower=forecast.slots[0].nominalPower, maximumEnergy=forecast.slots[0].nominalEnergy)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Success) - self.step("21a") + self.step("22a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("22") + self.step("23") await self.send_cancel_request_command() - self.step("22a") + self.step("23a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("23") + self.step("24") await self.send_cancel_request_command(expected_status=Status.InvalidInState) - self.step("24") + self.step("25") await self.send_test_event_trigger_constraint_based_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_8.py b/src/python_testing/TC_DEM_2_8.py index 12200eb7c7b7e3..1b1a2a31537098 100644 --- a/src/python_testing/TC_DEM_2_8.py +++ b/src/python_testing/TC_DEM_2_8.py @@ -34,7 +34,7 @@ import chip.clusters as Clusters from chip.interaction_model import Status -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -59,76 +59,77 @@ def pics_TC_DEM_2_8(self): def steps_TC_DEM_2_8(self) -> list[TestStep]: """Execute the test steps.""" 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("3b", "TH reads Forecast attribute.", + 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. Verify ConstraintBasedAdjustment feature is supported on the cluster. Verify StateForecastReporting feature is supported on the cluster. Verify PowerForecastReporting feature is not supported on the cluster."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include valid slots[0].ManufacturerESAState"), - TestStep("3c", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("4", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()-10, Duration=20, LoadControl=0}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("5", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+20, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+50, Duration=20, LoadControl=0}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("6", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+30, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+40, Duration=20, LoadControl=0}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("7", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+30, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+50, Duration=20, LoadControl=0}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("8", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+50, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+30, Duration=20, LoadControl=0}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("9", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=101}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("10", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=-101}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("11", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("11a", "TH reads ESAState attribute.", - "Verify value is 0x01 (Online)"), - TestStep("11b", "TH reads OptOutState attribute.", - "Verify value is 0x02 (LocalOptOut)"), - TestStep("12", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=LocalOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("13", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("13a", "TH reads Forecast attribute.", + TestStep("4c", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("5", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()-10, Duration=20, LoadControl=0}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("6", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+20, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+50, Duration=20, LoadControl=0}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("7", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+30, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+40, Duration=20, LoadControl=0}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("8", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+30, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+50, Duration=20, LoadControl=0}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("9", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=now()+10, Duration=20, LoadControl=0}, constraints[1].{StartTime=now()+50, Duration=20, LoadControl=0}, constraints[2].{StartTime=now()+30, Duration=20, LoadControl=0}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("10", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=101}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("11", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=-101}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("12", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("12a", "TH reads from the DUT the ESAState", + "Value has to be 0x01 (Online)"), + TestStep("12b", "TH reads from the DUT the OptOutState", + "Value has to be 0x02 (LocalOptOut)"), + TestStep("13", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=LocalOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("14", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("14a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("14", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("14a", "TH reads Forecast attribute.", + TestStep("15", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("15a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("15", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("15a", "TH reads Forecast attribute.", + TestStep("16", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("16a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=GridOptimization"), - TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("16a", "TH reads OptOutState attribute.", - "Verify value is 0x03 (OptOut)"), - TestStep("16b", "TH reads Forecast attribute.", + TestStep("17", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("17a", "TH reads from the DUT the OptOutState", + "Value has to be 0x03 (OptOut)"), + TestStep("17b", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("17", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization.", - "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), - TestStep("18", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("18a", "TH reads OptOutState attribute.", - "Verify value is 0x00 (NoOptOut)"), - TestStep("19", "TH sends RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=LocalOptimization.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("19a", "TH reads Forecast attribute.", + TestStep("18", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=GridOptimization", + "Verify DUT responds w/ status CONSTRAINT_ERROR(0x87)"), + TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("19a", "TH reads from the DUT the OptOutState", + "Value has to be 0x00 (NoOptOut)"), + TestStep("20", "TH sends command RequestConstraintBasedPowerForecast with constraints[0].{StartTime=Forecast.StartTime, Duration=Forecast.Slots[0].DefaultDuration, LoadControl=1}, Cause=LocalOptimization", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("20a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=LocalOptimization"), - TestStep("20", "TH sends CancelRequest.", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("20a", "TH reads Forecast attribute.", + TestStep("21", "TH sends command CancelRequest", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("21a", "TH reads from the DUT the Forecast", "Value has to include ForecastUpdateReason=InternalOptimization"), - TestStep("21", "TH sends CancelRequest.", - "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), - TestStep("22", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Adjustment Test Event Clear.", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("22", "TH sends command CancelRequest", + "Verify DUT responds w/ status INVALID_IN_STATE(0xcb)"), + TestStep("23", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Constraints-based Adjustment Adjustment Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -140,29 +141,28 @@ async def test_TC_DEM_2_8(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_feature_map(must_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kConstraintBasedAdjustment, + Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting], + must_not_have_features=[Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting]) self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_constraint_based_adjustment() - self.step("3a") + self.step("4a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("3b") + self.step("4b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_is_not_none(forecast.slots[0].manufacturerESAState) - self.step("3c") + self.step("4c") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("4") + self.step("5") # Matter UTC is time since 00:00:00 1/1/2000 now = self.get_current_utc_time_in_seconds() @@ -170,7 +170,7 @@ async def test_TC_DEM_2_8(self): startTime=now - 10, duration=20, loadControl=0)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("5") + self.step("6") # Matter UTC is time since 00:00:00 1/1/2000 now = self.get_current_utc_time_in_seconds() @@ -179,7 +179,7 @@ async def test_TC_DEM_2_8(self): Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 50, duration=20, loadControl=0)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("6") + self.step("7") # Matter UTC is time since 00:00:00 1/1/2000 now = self.get_current_utc_time_in_seconds() @@ -188,7 +188,7 @@ async def test_TC_DEM_2_8(self): Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 40, duration=20, loadControl=0)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("7") + self.step("8") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 30, duration=20, loadControl=0), @@ -196,7 +196,7 @@ async def test_TC_DEM_2_8(self): Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 50, duration=20, loadControl=0)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("8") + self.step("9") now = self.get_current_utc_time_in_seconds() constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 10, duration=20, loadControl=0), @@ -204,102 +204,102 @@ async def test_TC_DEM_2_8(self): Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct(startTime=now + 30, duration=20, loadControl=0)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("9") + self.step("10") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=101)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("10") + self.step("11") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=-101)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("11") + self.step("12") await self.send_test_event_trigger_user_opt_out_local() - self.step("11a") + self.step("12a") await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) - self.step("11b") + self.step("12b") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) - self.step("12") + self.step("13") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=1)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.ConstraintError) - self.step("13") + self.step("14") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=1)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("13a") + self.step("14a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("14") + self.step("15") await self.send_cancel_request_command() - self.step("14a") + self.step("15a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("15") + self.step("16") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=1)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.Success) - self.step("15a") + self.step("16a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kGridOptimization) - self.step("16") + self.step("17") await self.send_test_event_trigger_user_opt_out_grid() - self.step("16a") + self.step("17a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) - self.step("16b") + self.step("17b") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("17") + self.step("18") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=1)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization, expected_status=Status.ConstraintError) - self.step("18") + self.step("19") await self.send_test_event_trigger_user_opt_out_clear_all() - self.step("18a") + self.step("19a") await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) - self.step("19") + self.step("20") constraintList = [Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct( startTime=forecast.startTime, duration=forecast.slots[0].defaultDuration, loadControl=1)] await self.send_request_constraint_based_forecast(constraintList, cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, expected_status=Status.Success) - self.step("19a") + self.step("20a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kLocalOptimization) - self.step("20") + self.step("21") await self.send_cancel_request_command() - self.step("20a") + self.step("21a") forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_equal(forecast.forecastUpdateReason, Clusters.DeviceEnergyManagement.Enums.ForecastUpdateReasonEnum.kInternalOptimization) - self.step("21") + self.step("22") await self.send_cancel_request_command(expected_status=Status.InvalidInState) - self.step("22") + self.step("23") await self.send_test_event_trigger_constraint_based_adjustment_clear() diff --git a/src/python_testing/TC_DEM_2_9.py b/src/python_testing/TC_DEM_2_9.py index de51b7a7960932..3acc4b7a517ece 100644 --- a/src/python_testing/TC_DEM_2_9.py +++ b/src/python_testing/TC_DEM_2_9.py @@ -23,7 +23,7 @@ # test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} # 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 0x7e --application evse +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x7c --application evse # 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 === @@ -33,7 +33,7 @@ import logging import chip.clusters as Clusters -from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts from TC_DEMTestBase import DEMTestBase @@ -58,18 +58,19 @@ def pics_TC_DEM_2_9(self): def steps_TC_DEM_2_9(self) -> list[TestStep]: """Execute the test steps.""" steps = [ - TestStep("1", "Commissioning, already done", - is_commissioning=True), - TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", - "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), - TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Test Event", - "Verify DUT responds with status SUCCESS(0x00)"), - TestStep("3a", "TH reads Forecast attribute.", + 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. Verify one of PowerForecastReporting or StateForecastReporting is supported but not both."), + 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.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Test Event", + "Verify DUT responds w/ status SUCCESS(0x00)"), + TestStep("4a", "TH reads from the DUT the Forecast", "Value has to include a valid slots[0].ManufacturerESAState"), - TestStep("3b", "TH reads Forecast attribute.", + TestStep("4b", "TH reads from the DUT the Forecast", "Value has to include valid slots[0].NominalPower, slots[0].MinPower, slots[0].MaxPower, slots[0].NominalEnergy"), - TestStep("4", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Test Event Clear", - "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("5", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Forecast Test Event Clear", + "Verify DUT responds w/ status SUCCESS(0x00)"), ] return steps @@ -81,27 +82,24 @@ async def test_TC_DEM_2_9(self): self.step("1") # Commission DUT - already done - # Subscribe to Events and when they are sent push them to a queue for checking later - events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) - await events_callback.start(self.default_controller, - self.dut_node_id, - self.matter_test_config.endpoint) - self.step("2") - await self.check_test_event_triggers_enabled() + await self.validate_pfr_or_sfr_in_feature_map() self.step("3") + await self.check_test_event_triggers_enabled() + + self.step("4") await self.send_test_event_trigger_forecast() - self.step("3a") + self.step("4a") feature_map = await self.read_dem_attribute_expect_success(attribute="FeatureMap") if feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting: forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") asserts.assert_is_not_none(forecast.slots[0].manufacturerESAState) else: - logging.info('Device does not support StateForecastReporting. Skipping step 3a') + logging.info('Device does not support StateForecastReporting. Skipping step 4a') - self.step("3b") + self.step("4b") if feature_map & Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting: forecast = await self.read_dem_attribute_expect_success(attribute="Forecast") @@ -110,9 +108,9 @@ async def test_TC_DEM_2_9(self): asserts.assert_is_not_none(forecast.slots[0].maxPower) asserts.assert_is_not_none(forecast.slots[0].nominalEnergy) else: - logging.info('Device does not support StateForecastReporting. Skipping step 3b') + logging.info('Device does not support PowerForecastReporting. Skipping step 4b') - self.step("4") + self.step("5") await self.send_test_event_trigger_forecast_clear() diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index bd1b32e671ad79..c5e92482836b67 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -430,18 +430,27 @@ def reset(self): self.flush_reports() - async def start(self, dev_ctrl, node_id: int, endpoint: int, fabric_filtered: bool = False, min_interval_sec: int = 0, max_interval_sec: int = 5) -> Any: + async def start(self, dev_ctrl, node_id: int, endpoint: int, fabric_filtered: bool = False, min_interval_sec: int = 0, max_interval_sec: int = 5, keepSubscriptions: bool = True) -> Any: """This starts a subscription for attributes on the specified node_id and endpoint. The cluster is specified when the class instance is created.""" self._subscription = await dev_ctrl.ReadAttribute( nodeid=node_id, attributes=[(endpoint, self._expected_cluster)], reportInterval=(int(min_interval_sec), int(max_interval_sec)), fabricFiltered=fabric_filtered, - keepSubscriptions=True + keepSubscriptions=keepSubscriptions ) self._subscription.SetAttributeUpdateCallback(self.__call__) return self._subscription + async def cancel(self): + """This cancels a subscription.""" + # Wait for the asyncio.CancelledError to be called before returning + try: + self._subscription.Shutdown() + await asyncio.sleep(5) + except asyncio.CancelledError: + pass + def __call__(self, path: TypedAttributePath, transaction: SubscriptionTransaction): """This is the subscription callback when an attribute report is received. It checks the report is from the expected_cluster and then posts it into the queue for later processing."""