diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 6f09b851b3498e..fbaf631aaf7733 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -452,6 +452,7 @@ jobs: --target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test \ + --target linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test \ --target linux-x64-python-bindings \ build \ --copy-artifacts-to objdir-clone \ @@ -475,6 +476,9 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-lock-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_DRLK_2_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_DeviceBasicComposition.py" --script-args "--storage-path admin_storage.json --manual-code 10054912339 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-lock-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_DeviceConformance.py" --script-args "--storage-path admin_storage.json --manual-code 10054912339 --bool-arg ignore_in_progress:True allow_provisional:True --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto --tests test_TC_IDM_10_2"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-energy-management-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_EEVSE_2_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-energy-management-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_EEVSE_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-energy-management-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_EEVSE_2_5.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_FAN_3_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_FAN_3_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_FAN_3_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' diff --git a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp index 0f204671a9feca..16d3a35b0a30b4 100644 --- a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp @@ -232,8 +232,9 @@ void EVSEManufacturer::FakeReadingsUpdate() // Update meter values // Avoid using floats - so we will do a basic rand() call which will generate a integer value between 0 and RAND_MAX - // first compute power as a mean + some random value in range 0 to mPowerRandomness_mW - int64_t power = (rand() % gFakeReadingsData.mPowerRandomness_mW); + // first compute power as a mean + some random value in range +/- mPowerRandomness_mW + int64_t power = + (static_cast(rand()) % (2 * gFakeReadingsData.mPowerRandomness_mW)) - gFakeReadingsData.mPowerRandomness_mW; power += gFakeReadingsData.mPower_mW; // add in the base power // TODO call the EPM cluster to send a power reading diff --git a/src/python_testing/TC_EEVSE_2_2.py b/src/python_testing/TC_EEVSE_2_2.py index 1651f4daa4040b..0fcf6561e0c3ad 100644 --- a/src/python_testing/TC_EEVSE_2_2.py +++ b/src/python_testing/TC_EEVSE_2_2.py @@ -21,9 +21,9 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts -from TC_EEVSE_Utils import EEVSEBaseTestHelper, EventChangeCallback +from TC_EEVSE_Utils import EEVSEBaseTestHelper logger = logging.getLogger(__name__) @@ -123,7 +123,7 @@ async def test_TC_EEVSE_2_2(self): self.step("4") await self.send_test_event_trigger_pluggedin() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVConnected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVConnected) self.step("4a") await self.check_evse_attribute("State", Clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand) @@ -147,7 +147,7 @@ async def test_TC_EEVSE_2_2(self): self.step("6") await self.send_test_event_trigger_charge_demand() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStarted) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStarted) self.step("6a") await self.check_evse_attribute("State", expected_state) @@ -172,7 +172,7 @@ async def test_TC_EEVSE_2_2(self): # Sleep for the charging duration plus a couple of seconds to check it has stopped time.sleep(charging_duration + 2) # check EnergyTransferredStoped (EvseStopped) - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStopped) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStopped) expected_reason = Clusters.EnergyEvse.Enums.EnergyTransferStoppedReasonEnum.kEVSEStopped self.validate_energy_transfer_stopped_event(event_data, session_id, expected_state, expected_reason) @@ -188,7 +188,7 @@ async def test_TC_EEVSE_2_2(self): max_charge_current = 12000 await self.send_enable_charge_command(charge_until=charge_until, min_charge=min_charge_current, max_charge=max_charge_current) - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStarted) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStarted) self.step("8a") await self.check_evse_attribute("State", Clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging) @@ -228,7 +228,7 @@ async def test_TC_EEVSE_2_2(self): self.step("10") await self.send_test_event_trigger_charge_demand_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStopped) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStopped) expected_reason = Clusters.EnergyEvse.Enums.EnergyTransferStoppedReasonEnum.kEVStopped self.validate_energy_transfer_stopped_event(event_data, session_id, expected_state, expected_reason) @@ -239,7 +239,7 @@ async def test_TC_EEVSE_2_2(self): await self.send_test_event_trigger_charge_demand() # Check we get EnergyTransferStarted again await self.send_enable_charge_command(charge_until=charge_until, min_charge=min_charge_current, max_charge=max_charge_current) - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStarted) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStarted) self.validate_energy_transfer_started_event(event_data, session_id, expected_state, expected_max_charge) self.step("11a") @@ -247,7 +247,7 @@ async def test_TC_EEVSE_2_2(self): self.step("12") await self.send_test_event_trigger_charge_demand_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStopped) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStopped) expected_reason = Clusters.EnergyEvse.Enums.EnergyTransferStoppedReasonEnum.kEVStopped self.validate_energy_transfer_stopped_event(event_data, session_id, expected_state, expected_reason) @@ -256,7 +256,7 @@ async def test_TC_EEVSE_2_2(self): self.step("13") await self.send_test_event_trigger_pluggedin_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVNotDetected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVNotDetected) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand self.validate_ev_not_detected_event(event_data, session_id, expected_state, expected_duration=0, expected_charged=0) @@ -280,13 +280,13 @@ async def test_TC_EEVSE_2_2(self): session_id = session_id + 1 # Check we get a new EVConnected event with updated session ID - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVConnected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVConnected) self.validate_ev_connected_event(event_data, session_id) self.step("14a") await self.send_test_event_trigger_charge_demand() expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging # This is the value at the event time - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStarted) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStarted) self.validate_energy_transfer_started_event(event_data, session_id, expected_state, expected_max_charge) self.step("14b") @@ -295,7 +295,7 @@ async def test_TC_EEVSE_2_2(self): self.step("15") await self.send_disable_command() expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging # This is the value prior to stopping - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStopped) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStopped) expected_reason = Clusters.EnergyEvse.Enums.EnergyTransferStoppedReasonEnum.kEVSEStopped self.validate_energy_transfer_stopped_event(event_data, session_id, expected_state, expected_reason) @@ -307,7 +307,7 @@ async def test_TC_EEVSE_2_2(self): self.step("17") await self.send_test_event_trigger_pluggedin_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVNotDetected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVNotDetected) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand self.validate_ev_not_detected_event(event_data, session_id, expected_state, expected_duration=0, expected_charged=0) diff --git a/src/python_testing/TC_EEVSE_2_4.py b/src/python_testing/TC_EEVSE_2_4.py index 63adbe5a8563ab..9ccad2fdb692db 100644 --- a/src/python_testing/TC_EEVSE_2_4.py +++ b/src/python_testing/TC_EEVSE_2_4.py @@ -20,8 +20,8 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main -from TC_EEVSE_Utils import EEVSEBaseTestHelper, EventChangeCallback +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from TC_EEVSE_Utils import EEVSEBaseTestHelper logger = logging.getLogger(__name__) @@ -99,7 +99,7 @@ async def test_TC_EEVSE_2_4(self): self.step("4") await self.send_test_event_trigger_pluggedin() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVConnected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVConnected) self.step("4a") await self.check_evse_attribute("State", Clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand) @@ -117,7 +117,7 @@ async def test_TC_EEVSE_2_4(self): self.step("6") await self.send_test_event_trigger_charge_demand() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStarted) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStarted) self.step("6a") await self.check_evse_attribute("State", Clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging) @@ -127,7 +127,7 @@ async def test_TC_EEVSE_2_4(self): self.step("7") await self.send_test_event_trigger_evse_ground_fault() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.Fault) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.Fault) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging previous_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kNoError current_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kGroundFault @@ -141,7 +141,7 @@ async def test_TC_EEVSE_2_4(self): self.step("8") await self.send_test_event_trigger_evse_over_temperature_fault() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.Fault) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.Fault) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kFault previous_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kGroundFault current_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kOverTemperature @@ -155,7 +155,7 @@ async def test_TC_EEVSE_2_4(self): self.step("9") await self.send_test_event_trigger_evse_fault_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.Fault) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.Fault) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kFault previous_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kOverTemperature current_fault = Clusters.EnergyEvse.Enums.FaultStateEnum.kNoError @@ -169,11 +169,11 @@ async def test_TC_EEVSE_2_4(self): self.step("10") await self.send_test_event_trigger_charge_demand_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EnergyTransferStopped) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EnergyTransferStopped) self.step("11") await self.send_test_event_trigger_pluggedin_clear() - event_data = events_callback.WaitForEventReport(Clusters.EnergyEvse.Events.EVNotDetected) + event_data = events_callback.wait_for_event_report(Clusters.EnergyEvse.Events.EVNotDetected) expected_state = Clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand self.validate_ev_not_detected_event(event_data, session_id, expected_state, expected_duration=0, expected_charged=0) diff --git a/src/python_testing/TC_EEVSE_2_5.py b/src/python_testing/TC_EEVSE_2_5.py index 4a32b5a6d7ad6d..00150f263c7576 100644 --- a/src/python_testing/TC_EEVSE_2_5.py +++ b/src/python_testing/TC_EEVSE_2_5.py @@ -20,8 +20,8 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue from chip.interaction_model import Status -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main -from TC_EEVSE_Utils import EEVSEBaseTestHelper, EventChangeCallback +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from TC_EEVSE_Utils import EEVSEBaseTestHelper logger = logging.getLogger(__name__) diff --git a/src/python_testing/TC_EEVSE_Utils.py b/src/python_testing/TC_EEVSE_Utils.py index fb6bfa1f714d13..6b6b1395072ba0 100644 --- a/src/python_testing/TC_EEVSE_Utils.py +++ b/src/python_testing/TC_EEVSE_Utils.py @@ -16,45 +16,14 @@ import logging -import queue import chip.clusters as Clusters -from chip.clusters import ClusterObjects as ClusterObjects -from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction from chip.interaction_model import InteractionModelError, Status from mobly import asserts logger = logging.getLogger(__name__) -class EventChangeCallback: - def __init__(self, expected_cluster: ClusterObjects): - self._q = queue.Queue() - self._expected_cluster = expected_cluster - - async def start(self, dev_ctrl, node_id: int, endpoint: int): - self._subscription = await dev_ctrl.ReadEvent(node_id, - events=[(endpoint, self._expected_cluster, True)], reportInterval=(1, 5), - fabricFiltered=False, keepSubscriptions=True, autoResubscribe=False) - self._subscription.SetEventUpdateCallback(self.__call__) - - def __call__(self, res: EventReadResult, transaction: SubscriptionTransaction): - if res.Status == Status.Success and res.Header.ClusterId == self._expected_cluster.id: - logging.info( - f'Got subscription report for event on cluster {self._expected_cluster}: {res.Data}') - self._q.put(res) - - def WaitForEventReport(self, expected_event: ClusterObjects.ClusterEvent): - try: - res = self._q.get(block=True, timeout=10) - except queue.Empty: - asserts.fail("Failed to receive a report for the event {}".format(expected_event)) - - asserts.assert_equal(res.Header.ClusterId, expected_event.cluster_id, "Expected cluster ID not found in event report") - asserts.assert_equal(res.Header.EventId, expected_event.event_id, "Expected event ID not found in event report") - return res.Data - - class EEVSEBaseTestHelper: async def read_evse_attribute_expect_success(self, endpoint: int = None, attribute: str = ""): @@ -79,7 +48,7 @@ async def write_user_max_charge(self, endpoint: int = None, user_max_charge: int asserts.assert_equal(result[0].Status, Status.Success, "UserMaximumChargeCurrent write failed") async def send_enable_charge_command(self, endpoint: int = None, charge_until: int = None, timedRequestTimeoutMs: int = 3000, - min_charge: int = None, max_charge: int = None, expected_status: Status = Status.Success): + min_charge: int = 6000, max_charge: int = 32000, expected_status: Status = Status.Success): try: await self.send_single_cmd(cmd=Clusters.EnergyEvse.Commands.EnableCharging( chargingEnabledUntil=charge_until, @@ -110,34 +79,6 @@ async def send_start_diagnostics_command(self, endpoint: int = None, timedReques except InteractionModelError as e: asserts.assert_equal(e.status, expected_status, "Unexpected error returned") - async def send_test_event_triggers(self, enableKey: bytes = None, eventTrigger=0x0099000000000000): - # get the test event enable key or assume the default - # This can be passed in on command line using - # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f - if enableKey is None: - if 'enableKey' not in self.matter_test_config.global_test_params: - enableKey = bytes([b for b in range(16)]) - else: - enableKey = self.matter_test_config.global_test_params['enableKey'] - - try: - # GeneralDiagnosics cluster is meant to be on Endpoint 0 (Root) - await self.send_single_cmd(endpoint=0, - cmd=Clusters.GeneralDiagnostics.Commands.TestEventTrigger( - enableKey, - eventTrigger) - ) - - except InteractionModelError as e: - asserts.fail(f"Unexpected error returned - {e.status}") - - async def check_test_event_triggers_enabled(self): - full_attr = Clusters.GeneralDiagnostics.Attributes.TestEventTriggersEnabled - cluster = Clusters.Objects.GeneralDiagnostics - # GeneralDiagnosics cluster is meant to be on Endpoint 0 (Root) - test_event_enabled = await self.read_single_attribute_check_success(endpoint=0, cluster=cluster, attribute=full_attr) - asserts.assert_equal(test_event_enabled, True, "TestEventTriggersEnabled is False") - async def send_test_event_trigger_basic(self): await self.send_test_event_triggers(eventTrigger=0x0099000000000000) diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 4ddb4ce50fdf0e..2f3ca96d12038d 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -53,6 +53,7 @@ import chip.native from chip import discovery from chip.ChipStack import ChipStack +from chip.clusters import ClusterObjects as ClusterObjects from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction from chip.exceptions import ChipStackError from chip.interaction_model import InteractionModelError, Status @@ -273,6 +274,42 @@ def name(self) -> str: return self._name +class EventChangeCallback: + def __init__(self, expected_cluster: ClusterObjects): + """This class creates a queue to store received event callbacks, that can be checked by the test script + expected_cluster: is the cluster from which the events are expected + """ + self._q = queue.Queue() + self._expected_cluster = expected_cluster + + async def start(self, dev_ctrl, node_id: int, endpoint: int): + """This starts a subscription for events on the specified node_id and endpoint. The cluster is specified when the class instance is created.""" + self._subscription = await dev_ctrl.ReadEvent(node_id, + events=[(endpoint, self._expected_cluster, True)], reportInterval=(1, 5), + fabricFiltered=False, keepSubscriptions=True, autoResubscribe=False) + self._subscription.SetEventUpdateCallback(self.__call__) + + def __call__(self, res: EventReadResult, transaction: SubscriptionTransaction): + """This is the subscription callback when an event is received. + It checks the event is from the expected_cluster and then posts it into the queue for later processing.""" + if res.Status == Status.Success and res.Header.ClusterId == self._expected_cluster.id: + logging.info( + f'Got subscription report for event on cluster {self._expected_cluster}: {res.Data}') + self._q.put(res) + + def wait_for_event_report(self, expected_event: ClusterObjects.ClusterEvent, timeout: int = 10): + """This function allows a test script to block waiting for the specific event to arrive with a timeout. + It returns the event data so that the values can be checked.""" + try: + res = self._q.get(block=True, timeout=timeout) + except queue.Empty: + asserts.fail("Failed to receive a report for the event {}".format(expected_event)) + + asserts.assert_equal(res.Header.ClusterId, expected_event.cluster_id, "Expected cluster ID not found in event report") + asserts.assert_equal(res.Header.EventId, expected_event.event_id, "Expected event ID not found in event report") + return res.Data + + class InternalTestRunnerHooks(TestRunnerHooks): def start(self, count: int): @@ -847,6 +884,43 @@ async def send_single_cmd( result = await dev_ctrl.SendCommand(nodeid=node_id, endpoint=endpoint, payload=cmd, timedRequestTimeoutMs=timedRequestTimeoutMs) return result + async def send_test_event_triggers(self, eventTrigger: int, enableKey: bytes = None): + """This helper function sends a test event trigger to the General Diagnostics cluster on endpoint 0 + + The enableKey can be passed into the function, or omitted which will then + use the one provided to the script via --hex-arg enableKey: + if not it defaults to 0x000102030405060708090a0b0c0d0e0f + """ + # get the test event enable key or assume the default + # This can be passed in on command line using + # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f + if enableKey is None: + if 'enableKey' not in self.matter_test_config.global_test_params: + enableKey = bytes([b for b in range(16)]) + else: + enableKey = self.matter_test_config.global_test_params['enableKey'] + + try: + # GeneralDiagnostics cluster is meant to be on Endpoint 0 (Root) + await self.send_single_cmd(endpoint=0, + cmd=Clusters.GeneralDiagnostics.Commands.TestEventTrigger( + enableKey, + eventTrigger) + ) + + except InteractionModelError as e: + asserts.fail( + f"Sending TestEventTrigger resulted in Unexpected error. Are they enabled in DUT? Command returned - {e.status}") + + async def check_test_event_triggers_enabled(self): + """This cluster checks that the General Diagnostics cluster TestEventTriggersEnabled attribute is True. + It will assert and fail the test if not True.""" + full_attr = Clusters.GeneralDiagnostics.Attributes.TestEventTriggersEnabled + cluster = Clusters.Objects.GeneralDiagnostics + # GeneralDiagnostics cluster is meant to be on Endpoint 0 (Root) + test_event_enabled = await self.read_single_attribute_check_success(endpoint=0, cluster=cluster, attribute=full_attr) + asserts.assert_equal(test_event_enabled, True, "TestEventTriggersEnabled is False") + def print_step(self, stepnum: typing.Union[int, str], title: str) -> None: logging.info(f'***** Test Step {stepnum} : {title}')