Skip to content

Commit a43ce0e

Browse files
TC-VALCC-3.1: Allow immediate open of valve (project-chip#35851)
* TC-VALCC-3.1: Allow immediate open of valve If the valve can be opened before the command is complete or before the next read is done, the test will fail because it expects the transitioning phase to happen. In the spec: When the movement is complete, the device SHALL set the CurrentState attribute to the Open value. ^ this can happen before the end of the command. * fixup for 3.1 test * another fixup for 3.1 * Add close at start of test * linter * Restyled by clang-format * Restyled by isort * Add back the feature check * TC-VALCC-3.3: Allow immediate open * Linter * Fix 3.2 * couple little fixes * Restyled by isort * linter --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent d6bb79c commit a43ce0e

File tree

5 files changed

+214
-201
lines changed

5 files changed

+214
-201
lines changed

examples/all-clusters-app/linux/ValveControlDelegate.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ DataModel::Nullable<chip::Percent> ValveControlDelegate::HandleOpenValve(DataMod
3838
// In this demo application, the transition is considered instant,
3939
// so current level is set to the requested level and current state is set to kOpen.
4040
currentLevel = sLevel;
41-
Attributes::CurrentState::Set(kValveEndpoint, ValveConfigurationAndControl::ValveStateEnum::kOpen);
4241

4342
return DataModel::Nullable<chip::Percent>(currentLevel);
4443
}
@@ -48,8 +47,6 @@ CHIP_ERROR ValveControlDelegate::HandleCloseValve()
4847
sLastOpenDuration = 0;
4948
sLevel = 0;
5049
ReturnErrorOnFailure(ValveConfigurationAndControl::UpdateCurrentLevel(kValveEndpoint, sLevel));
51-
ReturnErrorOnFailure(
52-
ValveConfigurationAndControl::UpdateCurrentState(kValveEndpoint, ValveConfigurationAndControl::ValveStateEnum::kClosed));
5350
ChipLogProgress(NotSpecified, "Valve closed");
5451
return CHIP_NO_ERROR;
5552
}

src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,9 @@ CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable<Percent> level, Data
360360
if (!isDelegateNull(delegate))
361361
{
362362
DataModel::Nullable<Percent> cLevel = delegate->HandleOpenValve(level);
363-
if (HasFeature(ep, ValveConfigurationAndControl::Feature::kLevel))
363+
if (HasFeature(ep, ValveConfigurationAndControl::Feature::kLevel) && !cLevel.IsNull())
364364
{
365-
VerifyOrReturnError(Status::Success == CurrentLevel::Set(ep, cLevel), attribute_error);
365+
UpdateCurrentLevel(ep, cLevel.Value());
366366
}
367367
}
368368
// start countdown
@@ -376,14 +376,28 @@ CHIP_ERROR UpdateCurrentLevel(EndpointId ep, Percent currentLevel)
376376
if (HasFeature(ep, ValveConfigurationAndControl::Feature::kLevel))
377377
{
378378
VerifyOrReturnError(Status::Success == CurrentLevel::Set(ep, currentLevel), CHIP_IM_GLOBAL_STATUS(ConstraintError));
379-
return CHIP_NO_ERROR;
380379
}
381-
return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
380+
DataModel::Nullable<Percent> targetLevel = DataModel::NullNullable;
381+
TargetLevel::Get(ep, targetLevel);
382+
if (!targetLevel.IsNull() && currentLevel == targetLevel.Value())
383+
{
384+
targetLevel = DataModel::NullNullable;
385+
TargetLevel::Set(ep, targetLevel);
386+
UpdateCurrentState(ep, currentLevel == 0 ? ValveStateEnum::kClosed : ValveStateEnum::kOpen);
387+
}
388+
return CHIP_NO_ERROR;
382389
}
383390

384391
CHIP_ERROR UpdateCurrentState(EndpointId ep, ValveConfigurationAndControl::ValveStateEnum currentState)
385392
{
386393
VerifyOrReturnError(Status::Success == CurrentState::Set(ep, currentState), CHIP_IM_GLOBAL_STATUS(ConstraintError));
394+
DataModel::Nullable<ValveStateEnum> targetState = DataModel::NullNullable;
395+
TargetState::Get(ep, targetState);
396+
if (currentState == targetState.ValueOr(ValveStateEnum::kUnknownEnumValue))
397+
{
398+
targetState = DataModel::NullNullable;
399+
TargetState::Set(ep, targetState);
400+
}
387401
emitValveStateChangedEvent(ep, currentState);
388402
return CHIP_NO_ERROR;
389403
}

src/python_testing/TC_VALCC_3_1.py

+46-51
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,10 @@
3232
# quiet: true
3333
# === END CI TEST ARGUMENTS ===
3434

35-
import time
36-
3735
import chip.clusters as Clusters
3836
from chip.clusters.Types import NullValue
39-
from chip.interaction_model import InteractionModelError, Status
40-
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
37+
from chip.testing.matter_testing import (AttributeValue, ClusterAttributeChangeAccumulator, MatterBaseTest, TestStep,
38+
async_test_body, default_matter_test_main)
4139
from mobly import asserts
4240

4341

@@ -52,12 +50,16 @@ def desc_TC_VALCC_3_1(self) -> str:
5250
def steps_TC_VALCC_3_1(self) -> list[TestStep]:
5351
steps = [
5452
TestStep(1, "Commissioning, already done", is_commissioning=True),
55-
TestStep(2, "Send Open command"),
56-
TestStep(3, "Read TargetState attribute"),
57-
TestStep(4, "Read CurrentState attribute"),
58-
TestStep(5, "Send Close command"),
59-
TestStep(6, "Read TargetState attribute"),
60-
TestStep(7, "Read CurrentState attribute"),
53+
TestStep(2, "Set up a subscription to all attributes on the DUT"),
54+
TestStep(3, "Send a close command to the DUT and wait until the CurrentState is closed", "DUT returns SUCCESS"),
55+
TestStep(4, "Send Open command", "DUT returns SUCCESS"),
56+
TestStep(5, "Wait until TH receives and data report for TargetState set to NULL and an attribute report for CurrentState set to Open (ordering does not matter)",
57+
"Expected attribute reports are received"),
58+
TestStep(6, "Read CurrentState and TargetState attribute", "CurrentState is Open, TargetState is NULL"),
59+
TestStep(7, "Send Close command", "DUT returns SUCCESS"),
60+
TestStep(8, "Wait until TH receives and data report for TargetState set to NULL and an attribute report for CurrentState set to Closed (ordering does not matter)",
61+
"Expected attribute reports are received"),
62+
TestStep(9, "Read CurrentState and TargetState attribute", "CurrentState is Closed, TargetState is NULL"),
6163
]
6264
return steps
6365

@@ -72,62 +74,55 @@ async def test_TC_VALCC_3_1(self):
7274

7375
endpoint = self.get_endpoint(default=1)
7476

75-
self.step(1)
76-
attributes = Clusters.ValveConfigurationAndControl.Attributes
77+
self.step(1) # commissioning - already done
7778

7879
self.step(2)
79-
try:
80-
await self.send_single_cmd(cmd=Clusters.Objects.ValveConfigurationAndControl.Commands.Open(), endpoint=endpoint)
81-
except InteractionModelError as e:
82-
asserts.assert_equal(e.status, Status.Success, "Unexpected error returned")
83-
pass
80+
cluster = Clusters.ValveConfigurationAndControl
81+
attributes = cluster.Attributes
82+
attribute_subscription = ClusterAttributeChangeAccumulator(cluster)
83+
await attribute_subscription.start(self.default_controller, self.dut_node_id, endpoint)
8484

8585
self.step(3)
86-
target_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.TargetState)
87-
88-
asserts.assert_true(target_state_dut is not NullValue, "TargetState is null")
89-
asserts.assert_equal(target_state_dut, Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kOpen,
90-
"TargetState is not the expected value")
91-
92-
self.step(4)
86+
# Wait for the entire duration of the test because this valve may be slow. The test will time out before this does. That's fine.
87+
timeout = self.matter_test_config.timeout if self.matter_test_config.timeout is not None else self.default_timeout
88+
await self.send_single_cmd(cmd=cluster.Commands.Close(), endpoint=endpoint)
9389
current_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentState)
94-
asserts.assert_true(current_state_dut is not NullValue, "CurrentState is null")
95-
96-
while current_state_dut is Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kTransitioning:
97-
time.sleep(1)
98-
99-
current_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentState)
100-
asserts.assert_true(current_state_dut is not NullValue, "CurrentState is null")
90+
if current_state_dut != cluster.Enums.ValveStateEnum.kClosed:
91+
current_state_closed = AttributeValue(
92+
endpoint_id=endpoint, attribute=attributes.CurrentState, value=cluster.Enums.ValveStateEnum.kClosed)
93+
attribute_subscription.await_all_final_values_reported(
94+
expected_final_values=[current_state_closed], timeout_sec=timeout)
10195

102-
asserts.assert_equal(current_state_dut, Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kOpen,
103-
"CurrentState is not the expected value")
96+
self.step(4)
97+
attribute_subscription.reset()
98+
await self.send_single_cmd(cmd=Clusters.Objects.ValveConfigurationAndControl.Commands.Open(), endpoint=endpoint)
10499

105100
self.step(5)
106-
try:
107-
await self.send_single_cmd(cmd=Clusters.Objects.ValveConfigurationAndControl.Commands.Close(), endpoint=endpoint)
108-
except InteractionModelError as e:
109-
asserts.assert_equal(e.status, Status.Success, "Unexpected error returned")
110-
pass
101+
# Wait until the current state is open and the target state is Null.
102+
expected_final_state = [AttributeValue(endpoint_id=endpoint, attribute=attributes.TargetState, value=NullValue), AttributeValue(
103+
endpoint_id=endpoint, attribute=attributes.CurrentState, value=cluster.Enums.ValveStateEnum.kOpen)]
104+
attribute_subscription.await_all_final_values_reported(expected_final_values=expected_final_state, timeout_sec=timeout)
111105

112106
self.step(6)
113107
target_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.TargetState)
114-
115-
asserts.assert_true(target_state_dut is not NullValue, "TargetState is null")
116-
asserts.assert_equal(target_state_dut, Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kClosed,
117-
"TargetState is not the expected value")
118-
119-
self.step(7)
120108
current_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentState)
121-
asserts.assert_true(current_state_dut is not NullValue, "CurrentState is null")
109+
asserts.assert_equal(current_state_dut, cluster.Enums.ValveStateEnum.kOpen, "CurrentState is not open")
110+
asserts.assert_equal(target_state_dut, NullValue, "TargetState is not null")
122111

123-
while current_state_dut is Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kTransitioning:
124-
time.sleep(1)
112+
self.step(7)
113+
attribute_subscription.reset()
114+
await self.send_single_cmd(cmd=cluster.Commands.Close(), endpoint=endpoint)
125115

126-
current_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentState)
127-
asserts.assert_true(current_state_dut is not NullValue, "CurrentState is null")
116+
self.step(8)
117+
expected_final_state = [AttributeValue(endpoint_id=endpoint, attribute=attributes.TargetState, value=NullValue), AttributeValue(
118+
endpoint_id=endpoint, attribute=attributes.CurrentState, value=cluster.Enums.ValveStateEnum.kClosed)]
119+
attribute_subscription.await_all_final_values_reported(expected_final_values=expected_final_state, timeout_sec=timeout)
128120

129-
asserts.assert_equal(current_state_dut, Clusters.Objects.ValveConfigurationAndControl.Enums.ValveStateEnum.kClosed,
130-
"CurrentState is not the expected value")
121+
self.step(9)
122+
target_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.TargetState)
123+
current_state_dut = await self.read_valcc_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentState)
124+
asserts.assert_equal(current_state_dut, cluster.Enums.ValveStateEnum.kClosed, "CurrentState is not closed")
125+
asserts.assert_equal(target_state_dut, NullValue, "TargetState is not null")
131126

132127

133128
if __name__ == "__main__":

0 commit comments

Comments
 (0)