Skip to content

Commit

Permalink
[HVAC] Clear ActivePresetHandle attribute when changing relevant setp…
Browse files Browse the repository at this point in the history
…oint attributes
  • Loading branch information
hasty committed Aug 27, 2024
1 parent f299484 commit 04b18d3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2217,6 +2217,7 @@
}; \
const EmberAfGenericClusterFunction chipFuncArrayThermostatServer[] = { \
(EmberAfGenericClusterFunction) emberAfThermostatClusterServerInitCallback, \
(EmberAfGenericClusterFunction) MatterThermostatClusterServerAttributeChangedCallback, \
(EmberAfGenericClusterFunction) MatterThermostatClusterServerShutdownCallback, \
(EmberAfGenericClusterFunction) MatterThermostatClusterServerPreAttributeChangedCallback, \
}; \
Expand Down Expand Up @@ -3756,7 +3757,7 @@
.attributes = ZAP_ATTRIBUTE_INDEX(616), \
.attributeCount = 26, \
.clusterSize = 72, \
.mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(SHUTDOWN_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \
.mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION) | ZAP_CLUSTER_MASK(SHUTDOWN_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \
.functions = chipFuncArrayThermostatServer, \
.acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 241 ), \
.generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 246 ), \
Expand Down
51 changes: 51 additions & 0 deletions src/app/clusters/thermostat-server/thermostat-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,52 @@ void ThermostatAttrAccess::OnFabricRemoved(const FabricTable & fabricTable, Fabr
}
}

void MatterThermostatClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath)
{
uint32_t flags;
if (FeatureMap::Get(attributePath.mEndpointId, &flags) != Status::Success)
{
ChipLogError(Zcl, "MatterThermostatClusterServerAttributeChangedCallback: could not get feature flags");
return;
}

auto featureMap = chip::BitMask<Feature, uint32_t>(flags);
if (!featureMap.Has(Feature::kPresets))
{
// This server does not support presets, so nothing to do
return;
}

bool occupied = true;
if (featureMap.Has(Feature::kOccupancy))
{
chip::BitMask<OccupancyBitmap, uint8_t> occupancy;
if (Occupancy::Get(attributePath.mEndpointId, &occupancy) == Status::Success)
{
occupied = occupancy.Has(OccupancyBitmap::kOccupied);
}
}

bool clearActivePreset = false;
switch (attributePath.mAttributeId)
{
case OccupiedHeatingSetpoint::Id:
case OccupiedCoolingSetpoint::Id:
clearActivePreset = occupied;
break;
case UnoccupiedHeatingSetpoint::Id:
case UnoccupiedCoolingSetpoint::Id:
clearActivePreset = !occupied;
break;
}
if (!clearActivePreset)
{
return;
}
ChipLogProgress(Zcl, "Setting active preset to null");
gThermostatAttrAccess.SetActivePreset(attributePath.mEndpointId, std::nullopt);
}

} // namespace Thermostat
} // namespace Clusters
} // namespace app
Expand Down Expand Up @@ -762,6 +808,11 @@ MatterThermostatClusterServerPreAttributeChangedCallback(const app::ConcreteAttr
}
}

void MatterThermostatClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath)
{
Thermostat::MatterThermostatClusterServerAttributeChangedCallback(attributePath);
}

bool emberAfThermostatClusterClearWeeklyScheduleCallback(app::CommandHandler * commandObj,
const app::ConcreteCommandPath & commandPath,
const Commands::ClearWeeklySchedule::DecodableType & commandData)
Expand Down
1 change: 1 addition & 0 deletions src/app/clusters/thermostat-server/thermostat-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class ThermostatAttrAccess : public chip::app::AttributeAccessInterface, public
friend void TimerExpiredCallback(System::Layer * systemLayer, void * callbackContext);

friend void MatterThermostatClusterServerShutdownCallback(EndpointId endpoint);
friend void MatterThermostatClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath);

friend bool emberAfThermostatClusterSetActivePresetRequestCallback(
CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
Expand Down
1 change: 1 addition & 0 deletions src/app/common/templates/config-data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ ClustersWithAttributeChangedFunctions:
- Pump Configuration and Control
- Window Covering
- Fan Control
- Thermostat

ClustersWithShutdownFunctions:
- Barrier Control
Expand Down
12 changes: 12 additions & 0 deletions src/python_testing/TC_TSTAT_4_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ async def test_TC_TSTAT_4_2(self):
logger.info(f"Rx'd Presets: {presets}")
asserts.assert_equal(presets, new_presets_with_handle, "Presets were not updated which is not expected")

# Send the SetActivePresetRequest command
await self.send_set_active_preset_handle_request_command(value=b'\x03')

activePresetHandle = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.ActivePresetHandle)

self.step("5")
if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")):

Expand Down Expand Up @@ -323,6 +328,13 @@ async def test_TC_TSTAT_4_2(self):
# Send the AtomicRequest commit command and expect InvalidInState for presets.
await self.send_atomic_request_commit_command(expected_overall_status=Status.Failure, expected_preset_status=Status.InvalidInState)

# Write the occupied cooling setpoint to a different value
await self.write_single_attribute(attribute_value=cluster.Attributes.OccupiedCoolingSetpoint(2300), endpoint_id=endpoint)

activePresetHandle = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.ActivePresetHandle)
logger.info(f"Rx'd ActivePresetHandle: {activePresetHandle}")
asserts.assert_equal(activePresetHandle, NullValue, "Active preset handle was not cleared as expected")

self.step("7")
if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")):

Expand Down

0 comments on commit 04b18d3

Please sign in to comment.