From e940111b5df02b764dd2231c96aeb203be545183 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Thu, 27 Apr 2023 17:53:53 +0100 Subject: [PATCH 1/8] Updated fan-control-server with better support for feature checking, step command handler and checks around the supported attributes in the pre-callback --- .../fan-control-server/fan-control-server.cpp | 256 +++++++++++++----- 1 file changed, 192 insertions(+), 64 deletions(-) diff --git a/src/app/clusters/fan-control-server/fan-control-server.cpp b/src/app/clusters/fan-control-server/fan-control-server.cpp index 9d3a36e1f6a9f2..5a524179073007 100644 --- a/src/app/clusters/fan-control-server/fan-control-server.cpp +++ b/src/app/clusters/fan-control-server/fan-control-server.cpp @@ -28,7 +28,10 @@ #include #include #include +#include +#include #include +#include #include #include @@ -57,6 +60,45 @@ EmberAfStatus SetFanModeToOff(EndpointId endpointId) return status; } +bool HasFeature(EndpointId endpoint, FanControlFeature feature) +{ + bool success; + uint32_t featureMap; + success = (Attributes::FeatureMap::Get(endpoint, &featureMap) == EMBER_ZCL_STATUS_SUCCESS); + + return success ? ((featureMap & to_underlying(feature)) != 0) : false; +} + +inline bool SupportsMultiSpeed(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kMultiSpeed); +} + +inline bool SupportsAuto(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kAuto); +} + +inline bool SupportsRocking(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kRocking); +} + +inline bool SupportsWind(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kWind); +} + +inline bool SupportsStep(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kStep); +} + +inline bool SupportsAirflowDirection(chip::EndpointId endpointId) +{ + return HasFeature(endpointId, FanControlFeature::kAirflowDirection); +} + } // anonymous namespace // ============================================================================= @@ -73,11 +115,72 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute switch (attributePath.mAttributeId) { - case SpeedSetting::Id: - // Check if the SpeedSetting is null. - if (NumericAttributeTraits::IsNullValue(*value)) + case FanMode::Id: { + if (*value == to_underlying(FanModeType::kOn)) + { + *value = static_cast(FanModeType::kHigh); + res = Status::Success; + } + else if (*value == to_underlying(FanModeType::kSmart)) + { + FanModeSequenceType fanModeSequence; + FanModeSequence::Get(attributePath.mEndpointId, &fanModeSequence); + if ((fanModeSequence == FanModeSequenceType::kOffLowHighAuto) || + (fanModeSequence == FanModeSequenceType::kOffLowMedHighAuto)) + { + *value = static_cast(FanModeType::kAuto); + } + else + { + *value = static_cast(FanModeType::kHigh); + } + res = Status::Success; + } + break; + } + case SpeedSetting::Id: { + if (SupportsMultiSpeed(attributePath.mEndpointId)) { + // Check if the SpeedSetting is null. + if (NumericAttributeTraits::IsNullValue(*value)) + { + if (gWriteFromClusterLogic) + { + res = Status::Success; + gWriteFromClusterLogic = false; + } + else + { + res = Status::WriteIgnored; + } + } + else + { + uint8_t speedMax; + EmberAfStatus status = SpeedMax::Get(attributePath.mEndpointId, &speedMax); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, Status::ConstraintError); + + if (*value <= speedMax) + { + res = Status::Success; + } + else + { + res = Status::ConstraintError; + } + } + } + else + { + res = Status::UnsupportedAttribute; + } + break; + } + case PercentSetting::Id: { + // Check if the PercentSetting is null. + if (NumericAttributeTraits::IsNullValue(*value)) + { if (gWriteFromClusterLogic) { res = Status::Success; @@ -90,11 +193,16 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute } else { - uint8_t speedMax; - EmberAfStatus status = SpeedMax::Get(attributePath.mEndpointId, &speedMax); - VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, Status::ConstraintError); - - if (*value <= speedMax) + res = Status::Success; + } + break; + } + case RockSetting::Id: { + if (SupportsRocking(attributePath.mEndpointId)) + { + uint8_t rockSupport; + RockSupport::Get(attributePath.mEndpointId, &rockSupport); + if ((*value & rockSupport) == *value) { res = Status::Success; } @@ -103,25 +211,41 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute res = Status::ConstraintError; } } + else + { + res = Status::UnsupportedAttribute; + } break; - case PercentSetting::Id: { - // Check if the PercentSetting is null. - if (NumericAttributeTraits::IsNullValue(*value)) + } + case WindSupport::Id: { + if (SupportsWind(attributePath.mEndpointId)) { - if (gWriteFromClusterLogic) + uint8_t windSupport; + WindSupport::Get(attributePath.mEndpointId, &windSupport); + if ((*value & windSupport) == *value) { - res = Status::Success; - gWriteFromClusterLogic = false; + res = Status::Success; } else { - res = Status::WriteIgnored; + res = Status::ConstraintError; } } else + { + res = Status::UnsupportedAttribute; + } + break; + } + case AirflowDirection::Id: { + if (!SupportsAirflowDirection(attributePath.mEndpointId)) { res = Status::Success; } + else + { + res = Status::UnsupportedAttribute; + } break; } default: @@ -134,17 +258,6 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAttributePath & attributePath) { - bool multiSpeedSupported = false; - - { - uint32_t ourFeatureMap; - if (FeatureMap::Get(attributePath.mEndpointId, &ourFeatureMap) == EMBER_ZCL_STATUS_SUCCESS) - { - if (ourFeatureMap & to_underlying(FanControlFeature::kMultiSpeed)) - multiSpeedSupported = true; - } - } - switch (attributePath.mAttributeId) { case FanMode::Id: { @@ -164,7 +277,7 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(Zcl, "Failed to write PercentCurrent with error: 0x%02x", status)); - if (multiSpeedSupported) + if (SupportsMultiSpeed(attributePath.mEndpointId)) { status = SpeedSetting::Set(attributePath.mEndpointId, 0); VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, @@ -185,7 +298,7 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(Zcl, "Failed to write PercentSetting with error: 0x%02x", status)); - if (multiSpeedSupported) + if (SupportsMultiSpeed(attributePath.mEndpointId)) { gWriteFromClusterLogic = true; status = SpeedSetting::SetNull(attributePath.mEndpointId); @@ -208,7 +321,7 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", status)); } - if (multiSpeedSupported) + if (SupportsMultiSpeed(attributePath.mEndpointId)) { // Adjust SpeedSetting from a percent value change for PercentSetting // speed = ceil( SpeedMax * (percent * 0.01) ) @@ -231,53 +344,68 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(Zcl, "Failed to set SpeedSetting with error: 0x%02x", status)); } - - status = SpeedCurrent::Set(attributePath.mEndpointId, speedSetting); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, - ChipLogError(Zcl, "Failed to set SpeedCurrent with error: 0x%02x", status)); } break; } case SpeedSetting::Id: { - DataModel::Nullable speedSetting; - EmberAfStatus status = SpeedSetting::Get(attributePath.mEndpointId, speedSetting); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status && !speedSetting.IsNull()); - - // If SpeedSetting is set to 0, the server SHALL set the FanMode attribute value to Off. - if (speedSetting.Value() == 0) + if (SupportsMultiSpeed(attributePath.mEndpointId)) { - status = SetFanModeToOff(attributePath.mEndpointId); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, - ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", status)); - } - - // Adjust PercentSetting from a speed value change for SpeedSetting - // percent = floor( speed/SpeedMax * 100 ) - uint8_t speedMax; - status = SpeedMax::Get(attributePath.mEndpointId, &speedMax); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", status)); + DataModel::Nullable speedSetting; + EmberAfStatus status = SpeedSetting::Get(attributePath.mEndpointId, speedSetting); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status && !speedSetting.IsNull()); - DataModel::Nullable currentPercentSetting; - status = PercentSetting::Get(attributePath.mEndpointId, currentPercentSetting); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, - ChipLogError(Zcl, "Failed to get PercentSetting with error: 0x%02x", status)); + // If SpeedSetting is set to 0, the server SHALL set the FanMode attribute value to Off. + if (speedSetting.Value() == 0) + { + status = SetFanModeToOff(attributePath.mEndpointId); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", status)); + } - float speed = speedSetting.Value(); - uint8_t percentSetting = static_cast(speed / speedMax * 100); + // Adjust PercentSetting from a speed value change for SpeedSetting + // percent = floor( speed/SpeedMax * 100 ) + uint8_t speedMax; + status = SpeedMax::Get(attributePath.mEndpointId, &speedMax); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", status)); - if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value()) - { - status = PercentSetting::Set(attributePath.mEndpointId, percentSetting); + DataModel::Nullable currentPercentSetting; + status = PercentSetting::Get(attributePath.mEndpointId, currentPercentSetting); VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, - ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", status)); - } + ChipLogError(Zcl, "Failed to get PercentSetting with error: 0x%02x", status)); - status = PercentCurrent::Set(attributePath.mEndpointId, percentSetting); - VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, - ChipLogError(Zcl, "Failed to set PercentCurrent with error: 0x%02x", status)); - break; + float speed = speedSetting.Value(); + uint8_t percentSetting = static_cast(speed / speedMax * 100); + + if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value()) + { + status = PercentSetting::Set(attributePath.mEndpointId, percentSetting); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", status)); + } + } } default: break; } } + +bool emberAfFanControlClusterStepCallback(chip::app::CommandHandler * commandObj, + const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::FanControl::Commands::Step::DecodableType & commandData) +{ + /* + * TODO: Clarification needed in spec issue #6496 - if this is tied to the SpeedSetting attribute, then + * the attribute can be updated here, if it is supposed to be implementation specific, then the command + * will have to be handed off to an application specific callback which will require some sort of delegate. + */ + + Protocols::InteractionModel::Status status = Status::Success; + + if (!SupportsStep(commandPath.mEndpointId)) + { + status = Status::UnsupportedCommand; + } + commandObj->AddStatus(commandPath, status); + return true; +} From 18941d73a73f1cb8db5a58a9b8c5db668c1ff27e Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Thu, 27 Apr 2023 17:54:45 +0100 Subject: [PATCH 2/8] Updated fan-control-cluster.xml for TE1 for fall release and regenerated the generated code --- .../all-clusters-app.matter | 22 +++ .../all-clusters-common/all-clusters-app.zap | 45 ++++- .../all-clusters-minimal-app.matter | 12 ++ .../devices/rootnode_fan_7N2TobIlOX.matter | 12 ++ ...tnode_heatingcoolingunit_ncdGai1E5a.matter | 12 ++ .../rootnode_thermostat_bm3fb8dhYi.matter | 22 +++ .../data-model/chip/fan-control-cluster.xml | 23 +++ .../data_model/controller-clusters.matter | 22 +++ .../devicecontroller/ClusterReadMapping.java | 12 ++ .../devicecontroller/ClusterWriteMapping.java | 17 ++ .../CHIPAttributeTLVValueDecoder.cpp | 15 ++ .../zap-generated/CHIPClustersWrite-JNI.cpp | 52 ++++++ .../chip/devicecontroller/ChipClusters.java | 30 ++++ .../chip/devicecontroller/ChipIdLookup.java | 3 + .../python/chip/clusters/CHIPClusters.py | 7 + .../python/chip/clusters/Objects.py | 59 +++++++ .../MTRAttributeTLVValueDecoder.mm | 11 ++ .../CHIP/zap-generated/MTRBaseClusters.h | 36 ++++ .../CHIP/zap-generated/MTRBaseClusters.mm | 125 +++++++++++++ .../CHIP/zap-generated/MTRCallbackBridge.h | 141 +++++++++++++++ .../CHIP/zap-generated/MTRCallbackBridge.mm | 100 +++++++++++ .../CHIP/zap-generated/MTRClusterConstants.h | 6 + .../CHIP/zap-generated/MTRClusters.h | 12 ++ .../CHIP/zap-generated/MTRClusters.mm | 108 ++++++++++++ .../zap-generated/MTRCommandPayloadsObjc.h | 34 ++++ .../zap-generated/MTRCommandPayloadsObjc.mm | 37 ++++ .../zap-generated/attributes/Accessors.cpp | 31 ++++ .../zap-generated/attributes/Accessors.h | 5 + .../app-common/zap-generated/callback.h | 6 + .../zap-generated/cluster-enums-check.h | 24 +++ .../app-common/zap-generated/cluster-enums.h | 34 +++- .../zap-generated/cluster-objects.cpp | 58 +++++- .../zap-generated/cluster-objects.h | 65 +++++++ .../app-common/zap-generated/ids/Attributes.h | 4 + .../app-common/zap-generated/ids/Commands.h | 10 ++ .../zap-generated/cluster/Commands.h | 40 +++++ .../cluster/logging/DataModelLogger.cpp | 5 + .../zap-generated/cluster/Commands.h | 166 ++++++++++++++++++ 38 files changed, 1409 insertions(+), 14 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 7d5c990db66e81..7813a956563148 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -3158,6 +3158,16 @@ server cluster Thermostat = 513 { /** An interface for controlling a fan in a heating/cooling system. */ server cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -3182,6 +3192,8 @@ server cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { @@ -3211,12 +3223,21 @@ server cluster FanControl = 514 { attribute bitmap8 rockSetting = 8; readonly attribute bitmap8 windSupport = 9; attribute bitmap8 windSetting = 10; + attribute AirflowDirectionEnum airflowDirection = 11; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + request struct StepRequest { + DirectionEnum direction = 0; + boolean wrap = 1; + boolean lowestOff = 2; + } + + command Step(StepRequest): DefaultSuccess = 0; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ @@ -5220,6 +5241,7 @@ endpoint 1 { ram attribute rockSetting default = 0x00; ram attribute windSupport default = 0x00; ram attribute windSetting default = 0x00; + ram attribute airflowDirection default = 0; ram attribute featureMap default = 0x0F; ram attribute clusterRevision default = 2; } diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 7bdd60bf91a82f..60e349ae9db6fb 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -1,5 +1,5 @@ { - "featureLevel": 92, + "featureLevel": 95, "creator": "zap", "keyValuePairs": [ { @@ -16,6 +16,12 @@ } ], "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "version": "chip-v1" + }, { "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/zcl/zcl-with-test-extensions.json", @@ -23,12 +29,6 @@ "category": "matter", "version": 1, "description": "Matter SDK ZCL data with some extensions" - }, - { - "pathRelativity": "relativeToZap", - "path": "../../../src/app/zap-templates/app-templates.json", - "type": "gen-templates-json", - "version": "chip-v1" } ], "endpointTypes": [ @@ -15422,7 +15422,17 @@ "mfgCode": null, "define": "FAN_CONTROL_CLUSTER", "side": "client", - "enabled": 0 + "enabled": 0, + "commands": [ + { + "name": "Step", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ] }, { "name": "Fan Control", @@ -15608,6 +15618,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "AirflowDirection", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "AirflowDirectionEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, @@ -25498,5 +25524,6 @@ "endpointVersion": 1, "deviceIdentifier": 61442 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index 059bdeae17cece..012034b0ffe198 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -2717,6 +2717,16 @@ server cluster Thermostat = 513 { /** An interface for controlling a fan in a heating/cooling system. */ server cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -2741,6 +2751,8 @@ server cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index 4368aa72bdd833..baf6556543935d 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -1145,6 +1145,16 @@ server cluster FixedLabel = 64 { /** An interface for controlling a fan in a heating/cooling system. */ server cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -1169,6 +1179,8 @@ server cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index e1fc1b04c861bf..ed00d6cfeed8fd 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -1448,6 +1448,16 @@ client cluster Thermostat = 513 { /** An interface for controlling a fan in a heating/cooling system. */ server cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -1472,6 +1482,8 @@ server cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index bd7919c6893af6..bbf017e8644431 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1258,6 +1258,16 @@ server cluster Thermostat = 513 { /** An interface for controlling a fan in a heating/cooling system. */ client cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -1282,6 +1292,8 @@ client cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { @@ -1311,12 +1323,22 @@ client cluster FanControl = 514 { attribute optional bitmap8 rockSetting = 8; readonly attribute optional bitmap8 windSupport = 9; attribute optional bitmap8 windSetting = 10; + attribute optional AirflowDirectionEnum airflowDirection = 11; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + request struct StepRequest { + DirectionEnum direction = 0; + boolean wrap = 1; + boolean lowestOff = 2; + } + + /** The Step command speeds up or slows down the fan, in steps. */ + command Step(StepRequest): DefaultSuccess = 0; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ diff --git a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml index 53d7b4c107c483..e3f4616fb9c5a7 100644 --- a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml @@ -23,6 +23,8 @@ limitations under the License. + + @@ -65,6 +67,18 @@ limitations under the License. + + + + + + + + + + + + Fan Control HVAC @@ -86,5 +100,14 @@ limitations under the License. RockSetting WindSupport WindSetting + AirflowDirection + + + The Step command speeds up or slows down the fan, in steps. + + + + + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index a77f66684da4c4..ac37305df61133 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -3528,6 +3528,16 @@ client cluster Thermostat = 513 { /** An interface for controlling a fan in a heating/cooling system. */ client cluster FanControl = 514 { + enum AirflowDirectionEnum : ENUM8 { + kForward = 0; + kReverse = 1; + } + + enum DirectionEnum : ENUM8 { + kIncrease = 0; + kDecrease = 1; + } + enum FanModeSequenceType : ENUM8 { kOffLowMedHigh = 0; kOffLowHigh = 1; @@ -3552,6 +3562,8 @@ client cluster FanControl = 514 { kAuto = 0x2; kRocking = 0x4; kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; } bitmap RockSupportMask : BITMAP8 { @@ -3581,12 +3593,22 @@ client cluster FanControl = 514 { attribute optional bitmap8 rockSetting = 8; readonly attribute optional bitmap8 windSupport = 9; attribute optional bitmap8 windSetting = 10; + attribute optional AirflowDirectionEnum airflowDirection = 11; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + request struct StepRequest { + DirectionEnum direction = 0; + boolean wrap = 1; + boolean lowestOff = 2; + } + + /** The Step command speeds up or slows down the fan, in steps. */ + command Step(StepRequest): DefaultSuccess = 0; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index 509b9168a976d7..954b1a21285ed9 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -9580,6 +9580,18 @@ public Map> getReadAttributeMap() { readFanControlWindSettingCommandParams); readFanControlInteractionInfo.put( "readWindSettingAttribute", readFanControlWindSettingAttributeInteractionInfo); + Map readFanControlAirflowDirectionCommandParams = + new LinkedHashMap(); + InteractionInfo readFanControlAirflowDirectionAttributeInteractionInfo = + new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.FanControlCluster) cluster) + .readAirflowDirectionAttribute((ChipClusters.IntegerAttributeCallback) callback); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readFanControlAirflowDirectionCommandParams); + readFanControlInteractionInfo.put( + "readAirflowDirectionAttribute", readFanControlAirflowDirectionAttributeInteractionInfo); Map readFanControlGeneratedCommandListCommandParams = new LinkedHashMap(); InteractionInfo readFanControlGeneratedCommandListAttributeInteractionInfo = diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index 2dce6dab7f0433..ec95b2d0b6bae5 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -1719,6 +1719,23 @@ public Map> getWriteAttributeMap() { writeFanControlWindSettingCommandParams); writeFanControlInteractionInfo.put( "writeWindSettingAttribute", writeFanControlWindSettingAttributeInteractionInfo); + Map writeFanControlAirflowDirectionCommandParams = + new LinkedHashMap(); + CommandParameterInfo fanControlairflowDirectionCommandParameterInfo = + new CommandParameterInfo("value", Integer.class, Integer.class); + writeFanControlAirflowDirectionCommandParams.put( + "value", fanControlairflowDirectionCommandParameterInfo); + InteractionInfo writeFanControlAirflowDirectionAttributeInteractionInfo = + new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.FanControlCluster) cluster) + .writeAirflowDirectionAttribute( + (DefaultClusterCallback) callback, (Integer) commandArguments.get("value")); + }, + () -> new ClusterInfoMapping.DelegatedDefaultClusterCallback(), + writeFanControlAirflowDirectionCommandParams); + writeFanControlInteractionInfo.put( + "writeAirflowDirectionAttribute", writeFanControlAirflowDirectionAttributeInteractionInfo); writeAttributeMap.put("fanControl", writeFanControlInteractionInfo); Map writeThermostatUserInterfaceConfigurationInteractionInfo = new LinkedHashMap<>(); diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 4e02a196cc0db1..d9ba1cfab196fa 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -13999,6 +13999,21 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR cppValue, value); return value; } + case Attributes::AirflowDirection::Id: { + using TypeInfo = Attributes::AirflowDirection::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + static_cast(cppValue), value); + return value; + } case Attributes::GeneratedCommandList::Id: { using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; TypeInfo::DecodableType cppValue; diff --git a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp index 704671c5d5fa20..e1da5c63918c3c 100644 --- a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp +++ b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp @@ -5618,6 +5618,58 @@ JNI_METHOD(void, FanControlCluster, writeWindSettingAttribute) onFailure.release(); } +JNI_METHOD(void, FanControlCluster, writeAirflowDirectionAttribute) +(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) +{ + chip::DeviceLayer::StackLock lock; + ListFreer listFreer; + using TypeInfo = chip::app::Clusters::FanControl::Attributes::AirflowDirection::TypeInfo; + TypeInfo::Type cppValue; + + std::vector> cleanupByteArrays; + std::vector> cleanupStrings; + + cppValue = + static_cast>(chip::JniReferences::GetInstance().IntegerToPrimitive(value)); + + std::unique_ptr onSuccess( + Platform::New(callback), Platform::Delete); + VerifyOrReturn(onSuccess.get() != nullptr, + chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( + env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY)); + + std::unique_ptr onFailure( + Platform::New(callback), Platform::Delete); + VerifyOrReturn(onFailure.get() != nullptr, + chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( + env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY)); + + CHIP_ERROR err = CHIP_NO_ERROR; + FanControlCluster * cppCluster = reinterpret_cast(clusterPtr); + VerifyOrReturn(cppCluster != nullptr, + chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( + env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE)); + + auto successFn = chip::Callback::Callback::FromCancelable(onSuccess->Cancel()); + auto failureFn = chip::Callback::Callback::FromCancelable(onFailure->Cancel()); + + if (timedWriteTimeoutMs == nullptr) + { + err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall); + } + else + { + err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall, + chip::JniReferences::GetInstance().IntegerToPrimitive(timedWriteTimeoutMs)); + } + VerifyOrReturn( + err == CHIP_NO_ERROR, + chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error writing attribute", err)); + + onSuccess.release(); + onFailure.release(); +} + JNI_METHOD(void, ThermostatUserInterfaceConfigurationCluster, writeTemperatureDisplayModeAttribute) (JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) { diff --git a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java index 68cadaf318e3e4..d13acb7bfc5a8a 100644 --- a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java @@ -17690,6 +17690,24 @@ public void subscribeWindSettingAttribute( subscribeWindSettingAttribute(chipClusterPtr, callback, minInterval, maxInterval); } + public void readAirflowDirectionAttribute(IntegerAttributeCallback callback) { + readAirflowDirectionAttribute(chipClusterPtr, callback); + } + + public void writeAirflowDirectionAttribute(DefaultClusterCallback callback, Integer value) { + writeAirflowDirectionAttribute(chipClusterPtr, callback, value, null); + } + + public void writeAirflowDirectionAttribute( + DefaultClusterCallback callback, Integer value, int timedWriteTimeoutMs) { + writeAirflowDirectionAttribute(chipClusterPtr, callback, value, timedWriteTimeoutMs); + } + + public void subscribeAirflowDirectionAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + subscribeAirflowDirectionAttribute(chipClusterPtr, callback, minInterval, maxInterval); + } + public void readGeneratedCommandListAttribute(GeneratedCommandListAttributeCallback callback) { readGeneratedCommandListAttribute(chipClusterPtr, callback); } @@ -17852,6 +17870,18 @@ private native void writeWindSettingAttribute( private native void subscribeWindSettingAttribute( long chipClusterPtr, IntegerAttributeCallback callback, int minInterval, int maxInterval); + private native void readAirflowDirectionAttribute( + long chipClusterPtr, IntegerAttributeCallback callback); + + private native void writeAirflowDirectionAttribute( + long chipClusterPtr, + DefaultClusterCallback callback, + Integer value, + @Nullable Integer timedWriteTimeoutMs); + + private native void subscribeAirflowDirectionAttribute( + long chipClusterPtr, IntegerAttributeCallback callback, int minInterval, int maxInterval); + private native void readGeneratedCommandListAttribute( long chipClusterPtr, GeneratedCommandListAttributeCallback callback); diff --git a/src/controller/java/zap-generated/chip/devicecontroller/ChipIdLookup.java b/src/controller/java/zap-generated/chip/devicecontroller/ChipIdLookup.java index 3ec024468a2f3d..18e2b053be2ba5 100644 --- a/src/controller/java/zap-generated/chip/devicecontroller/ChipIdLookup.java +++ b/src/controller/java/zap-generated/chip/devicecontroller/ChipIdLookup.java @@ -2341,6 +2341,9 @@ public static String attributeIdToName(long clusterId, long attributeId) { if (attributeId == 10L) { return "WindSetting"; } + if (attributeId == 11L) { + return "AirflowDirection"; + } if (attributeId == 65528L) { return "GeneratedCommandList"; } diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 63da4fe4764472..0249c7a2ef6467 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -5304,6 +5304,13 @@ class ChipClusters: "reportable": True, "writable": True, }, + 0x0000000B: { + "attributeName": "AirflowDirection", + "attributeId": 0x0000000B, + "type": "int", + "reportable": True, + "writable": True, + }, 0x0000FFF8: { "attributeName": "GeneratedCommandList", "attributeId": 0x0000FFF8, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 951c635ea4ebfa..bb1e0eae35ac70 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -19301,6 +19301,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="rockSetting", Tag=0x00000008, Type=typing.Optional[uint]), ClusterObjectFieldDescriptor(Label="windSupport", Tag=0x00000009, Type=typing.Optional[uint]), ClusterObjectFieldDescriptor(Label="windSetting", Tag=0x0000000A, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="airflowDirection", Tag=0x0000000B, Type=typing.Optional[FanControl.Enums.AirflowDirectionEnum]), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), @@ -19320,6 +19321,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: rockSetting: 'typing.Optional[uint]' = None windSupport: 'typing.Optional[uint]' = None windSetting: 'typing.Optional[uint]' = None + airflowDirection: 'typing.Optional[FanControl.Enums.AirflowDirectionEnum]' = None generatedCommandList: 'typing.List[uint]' = None acceptedCommandList: 'typing.List[uint]' = None eventList: 'typing.List[uint]' = None @@ -19328,6 +19330,24 @@ def descriptor(cls) -> ClusterObjectDescriptor: clusterRevision: 'uint' = None class Enums: + class AirflowDirectionEnum(MatterIntEnum): + kForward = 0x00 + kReverse = 0x01 + # All received enum values that are not listed above will be mapped + # to kUnknownEnumValue. This is a helper enum value that should only + # be used by code to process how it handles receiving and unknown + # enum value. This specific should never be transmitted. + kUnknownEnumValue = 2, + + class DirectionEnum(MatterIntEnum): + kIncrease = 0x00 + kDecrease = 0x01 + # All received enum values that are not listed above will be mapped + # to kUnknownEnumValue. This is a helper enum value that should only + # be used by code to process how it handles receiving and unknown + # enum value. This specific should never be transmitted. + kUnknownEnumValue = 2, + class FanModeSequenceType(MatterIntEnum): kOffLowMedHigh = 0x00 kOffLowHigh = 0x01 @@ -19361,6 +19381,8 @@ class FanControlFeature(IntFlag): kAuto = 0x2 kRocking = 0x4 kWind = 0x8 + kStep = 0x10 + kAirflowDirection = 0x20 class RockSupportMask(IntFlag): kRockLeftRight = 0x1 @@ -19375,6 +19397,27 @@ class WindSupportMask(IntFlag): kSleepWind = 0x1 kNaturalWind = 0x2 + class Commands: + @dataclass + class Step(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x0202 + command_id: typing.ClassVar[int] = 0x00000000 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="direction", Tag=0, Type=FanControl.Enums.DirectionEnum), + ClusterObjectFieldDescriptor(Label="wrap", Tag=1, Type=bool), + ClusterObjectFieldDescriptor(Label="lowestOff", Tag=2, Type=bool), + ]) + + direction: 'FanControl.Enums.DirectionEnum' = 0 + wrap: 'bool' = False + lowestOff: 'bool' = False + class Attributes: @dataclass class FanMode(ClusterAttributeDescriptor): @@ -19552,6 +19595,22 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Optional[uint]' = None + @dataclass + class AirflowDirection(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x0202 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000000B + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Optional[FanControl.Enums.AirflowDirectionEnum]) + + value: 'typing.Optional[FanControl.Enums.AirflowDirectionEnum]' = None + @dataclass class GeneratedCommandList(ClusterAttributeDescriptor): @ChipUtility.classproperty diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 568ea996ca72d5..e3e61ae494b6b4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -10294,6 +10294,17 @@ id MTRDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::TLVReader & value = [NSNumber numberWithUnsignedChar:cppValue]; return value; } + case Attributes::AirflowDirection::Id: { + using TypeInfo = Attributes::AirflowDirection::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedChar:chip::to_underlying(cppValue)]; + return value; + } case Attributes::GeneratedCommandList::Id: { using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; TypeInfo::DecodableType cppValue; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index c2960dafd0aad1..41fd9e63e0657b 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -10416,6 +10416,13 @@ API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) queue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); +/** + * Command Step + * + * The Step command speeds up or slows down the fan, in steps. + */ +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; + - (void)readAttributeFanModeWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)writeAttributeFanModeWithValue:(NSNumber * _Nonnull)value @@ -10591,6 +10598,23 @@ API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); +- (void)readAttributeAirflowDirectionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion + MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value + completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value + params:(MTRWriteParams * _Nullable)params + completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; +- (void)subscribeAttributeAirflowDirectionWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler + MTR_NEWLY_AVAILABLE; ++ (void)readAttributeAirflowDirectionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer + endpoint:(NSNumber *)endpoint + queue:(dispatch_queue_t)queue + completion:(void (^)(NSNumber * _Nullable value, + NSError * _Nullable error))completion MTR_NEWLY_AVAILABLE; + - (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params @@ -21073,6 +21097,16 @@ typedef NS_OPTIONS(uint32_t, MTRThermostatFeature) { = 0x20, } API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); +typedef NS_ENUM(uint8_t, MTRFanControlAirflowDirection) { + MTRFanControlAirflowDirectionForward MTR_NEWLY_AVAILABLE = 0x00, + MTRFanControlAirflowDirectionReverse MTR_NEWLY_AVAILABLE = 0x01, +} MTR_NEWLY_AVAILABLE; + +typedef NS_ENUM(uint8_t, MTRFanControlDirection) { + MTRFanControlDirectionIncrease MTR_NEWLY_AVAILABLE = 0x00, + MTRFanControlDirectionDecrease MTR_NEWLY_AVAILABLE = 0x01, +} MTR_NEWLY_AVAILABLE; + typedef NS_ENUM(uint8_t, MTRFanControlFanModeSequenceType) { MTRFanControlFanModeSequenceTypeOffLowMedHigh API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x00, MTRFanControlFanModeSequenceTypeOffLowHigh API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x01, @@ -21097,6 +21131,8 @@ typedef NS_OPTIONS(uint32_t, MTRFanControlFeature) { MTRFanControlFeatureAuto API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x2, MTRFanControlFeatureRocking API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x4, MTRFanControlFeatureWind API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x8, + MTRFanControlFeatureStep MTR_NEWLY_AVAILABLE = 0x10, + MTRFanControlFeatureAirflowDirection MTR_NEWLY_AVAILABLE = 0x20, } API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); typedef NS_OPTIONS(uint8_t, MTRFanControlRockSupportMask) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 86a9e2d3c69d75..42e7d97f74f0b0 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -65198,6 +65198,45 @@ - (instancetype)initWithDevice:(MTRBaseDevice *)device endpointID:(NSNumber *)en return self; } +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params completion:(MTRStatusCompletion)completion +{ + // Make a copy of params before we go async. + params = [params copy]; + auto * bridge = new MTRCommandSuccessCallbackBridge( + self.callbackQueue, + ^(id _Nullable value, NSError * _Nullable error) { + completion(error); + }, + ^(ExchangeManager & exchangeManager, const SessionHandle & session, CommandSuccessCallbackType successCb, + MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) { + auto * typedBridge = static_cast(bridge); + Optional timedInvokeTimeoutMs; + Optional invokeTimeout; + ListFreer listFreer; + FanControl::Commands::Step::Type request; + if (params != nil) { + if (params.timedInvokeTimeoutMs != nil) { + params.timedInvokeTimeoutMs = MTRClampedNumber(params.timedInvokeTimeoutMs, @(1), @(UINT16_MAX)); + timedInvokeTimeoutMs.SetValue(params.timedInvokeTimeoutMs.unsignedShortValue); + } + if (params.serverSideProcessingTimeout != nil) { + // Clamp to a number of seconds that will not overflow 32-bit + // int when converted to ms. + auto * serverSideProcessingTimeout = MTRClampedNumber(params.serverSideProcessingTimeout, @(0), @(UINT16_MAX)); + invokeTimeout.SetValue(Seconds16(serverSideProcessingTimeout.unsignedShortValue)); + } + } + request.direction + = static_cast>(params.direction.unsignedCharValue); + request.wrap = params.wrap.boolValue; + request.lowestOff = params.lowestOff.boolValue; + + return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self->_endpoint, + timedInvokeTimeoutMs, invokeTimeout); + }); + std::move(*bridge).DispatchAction(self.device); +} + - (void)readAttributeFanModeWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { MTRReadParams * params = [[MTRReadParams alloc] init]; @@ -65904,6 +65943,87 @@ + (void)readAttributeWindSettingWithClusterStateCache:(MTRClusterStateCacheConta }); } +- (void)readAttributeAirflowDirectionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + MTRReadParams * params = [[MTRReadParams alloc] init]; + using TypeInfo = FanControl::Attributes::AirflowDirection::TypeInfo; + return MTRReadAttribute( + params, completion, self.callbackQueue, self.device, self->_endpoint, TypeInfo::GetClusterId(), TypeInfo::GetAttributeId()); +} + +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion +{ + [self writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull) value params:nil completion:completion]; +} +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value + params:(MTRWriteParams * _Nullable)params + completion:(MTRStatusCompletion)completion +{ + // Make a copy of params before we go async. + params = [params copy]; + value = [value copy]; + + auto * bridge = new MTRDefaultSuccessCallbackBridge( + self.callbackQueue, + ^(id _Nullable ignored, NSError * _Nullable error) { + completion(error); + }, + ^(ExchangeManager & exchangeManager, const SessionHandle & session, DefaultSuccessCallbackType successCb, + MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) { + chip::Optional timedWriteTimeout; + if (params != nil) { + if (params.timedWriteTimeout != nil) { + timedWriteTimeout.SetValue(params.timedWriteTimeout.unsignedShortValue); + } + } + + ListFreer listFreer; + using TypeInfo = FanControl::Attributes::AirflowDirection::TypeInfo; + TypeInfo::Type cppValue; + cppValue = static_cast>(value.unsignedCharValue); + + chip::Controller::FanControlCluster cppCluster(exchangeManager, session, self->_endpoint); + return cppCluster.WriteAttribute(cppValue, bridge, successCb, failureCb, timedWriteTimeout); + }); + std::move(*bridge).DispatchAction(self.device); +} + +- (void)subscribeAttributeAirflowDirectionWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = FanControl::Attributes::AirflowDirection::TypeInfo; + MTRSubscribeAttribute(params, subscriptionEstablished, reportHandler, self.callbackQueue, self.device, self->_endpoint, + TypeInfo::GetClusterId(), TypeInfo::GetAttributeId()); +} + ++ (void)readAttributeAirflowDirectionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer + endpoint:(NSNumber *)endpoint + queue:(dispatch_queue_t)queue + completion: + (void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + auto * bridge = new MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(queue, completion); + std::move(*bridge).DispatchLocalAction(clusterStateCacheContainer.baseDevice, + ^(FanControlClusterAirflowDirectionEnumAttributeCallback successCb, MTRErrorCallback failureCb) { + if (clusterStateCacheContainer.cppClusterStateCache) { + chip::app::ConcreteAttributePath path; + using TypeInfo = FanControl::Attributes::AirflowDirection::TypeInfo; + path.mEndpointId = static_cast([endpoint unsignedShortValue]); + path.mClusterId = TypeInfo::GetClusterId(); + path.mAttributeId = TypeInfo::GetAttributeId(); + TypeInfo::DecodableType value; + CHIP_ERROR err = clusterStateCacheContainer.cppClusterStateCache->Get(path, value); + if (err == CHIP_NO_ERROR) { + successCb(bridge, value); + } + return err; + } + return CHIP_ERROR_NOT_FOUND; + }); +} + - (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { MTRReadParams * params = [[MTRReadParams alloc] init]; @@ -66128,6 +66248,11 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @implementation MTRBaseClusterFanControl (Deprecated) +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params completionHandler:(MTRStatusCompletion)completionHandler +{ + [self stepWithParams:params completion:completionHandler]; +} + - (void)readAttributeFanModeWithCompletionHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completionHandler { [self readAttributeFanModeWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.h b/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.h index f3a7deead776d0..03dc8fa8992d38 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.h @@ -452,6 +452,13 @@ typedef void (*ThermostatClusterThermostatSystemModeAttributeCallback)(void *, chip::app::Clusters::Thermostat::ThermostatSystemMode); typedef void (*NullableThermostatClusterThermostatSystemModeAttributeCallback)( void *, const chip::app::DataModel::Nullable &); +typedef void (*FanControlClusterAirflowDirectionEnumAttributeCallback)(void *, + chip::app::Clusters::FanControl::AirflowDirectionEnum); +typedef void (*NullableFanControlClusterAirflowDirectionEnumAttributeCallback)( + void *, const chip::app::DataModel::Nullable &); +typedef void (*FanControlClusterDirectionEnumAttributeCallback)(void *, chip::app::Clusters::FanControl::DirectionEnum); +typedef void (*NullableFanControlClusterDirectionEnumAttributeCallback)( + void *, const chip::app::DataModel::Nullable &); typedef void (*FanControlClusterFanModeSequenceTypeAttributeCallback)(void *, chip::app::Clusters::FanControl::FanModeSequenceType); typedef void (*NullableFanControlClusterFanModeSequenceTypeAttributeCallback)( void *, const chip::app::DataModel::Nullable &); @@ -17776,6 +17783,140 @@ class MTRNullableThermostatClusterThermostatSystemModeAttributeCallbackSubscript MTRSubscriptionEstablishedHandler mEstablishedHandler; }; +class MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge + : public MTRCallbackBridge +{ +public: + MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler) : + MTRCallbackBridge(queue, handler, OnSuccessFn){}; + + MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler, + MTRActionBlock action) : + MTRCallbackBridge(queue, handler, action, OnSuccessFn){}; + + static void OnSuccessFn(void * context, chip::app::Clusters::FanControl::AirflowDirectionEnum value); +}; + +class MTRFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge + : public MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge +{ +public: + MTRFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge( + dispatch_queue_t queue, ResponseHandler handler, MTRActionBlock action, + MTRSubscriptionEstablishedHandler establishedHandler) : + MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(queue, handler, action), + mEstablishedHandler(establishedHandler) + {} + + void OnSubscriptionEstablished(); + using MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::KeepAliveOnCallback; + using MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::OnDone; + +private: + MTRSubscriptionEstablishedHandler mEstablishedHandler; +}; + +class MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge + : public MTRCallbackBridge +{ +public: + MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler) : + MTRCallbackBridge(queue, handler, OnSuccessFn){}; + + MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler, + MTRActionBlock action) : + MTRCallbackBridge(queue, handler, action, OnSuccessFn){}; + + static void OnSuccessFn(void * context, + const chip::app::DataModel::Nullable & value); +}; + +class MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge + : public MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge +{ +public: + MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge( + dispatch_queue_t queue, ResponseHandler handler, MTRActionBlock action, + MTRSubscriptionEstablishedHandler establishedHandler) : + MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge(queue, handler, action), + mEstablishedHandler(establishedHandler) + {} + + void OnSubscriptionEstablished(); + using MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::KeepAliveOnCallback; + using MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::OnDone; + +private: + MTRSubscriptionEstablishedHandler mEstablishedHandler; +}; + +class MTRFanControlClusterDirectionEnumAttributeCallbackBridge + : public MTRCallbackBridge +{ +public: + MTRFanControlClusterDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler) : + MTRCallbackBridge(queue, handler, OnSuccessFn){}; + + MTRFanControlClusterDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler, + MTRActionBlock action) : + MTRCallbackBridge(queue, handler, action, OnSuccessFn){}; + + static void OnSuccessFn(void * context, chip::app::Clusters::FanControl::DirectionEnum value); +}; + +class MTRFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge + : public MTRFanControlClusterDirectionEnumAttributeCallbackBridge +{ +public: + MTRFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge(dispatch_queue_t queue, ResponseHandler handler, + MTRActionBlock action, + MTRSubscriptionEstablishedHandler establishedHandler) : + MTRFanControlClusterDirectionEnumAttributeCallbackBridge(queue, handler, action), + mEstablishedHandler(establishedHandler) + {} + + void OnSubscriptionEstablished(); + using MTRFanControlClusterDirectionEnumAttributeCallbackBridge::KeepAliveOnCallback; + using MTRFanControlClusterDirectionEnumAttributeCallbackBridge::OnDone; + +private: + MTRSubscriptionEstablishedHandler mEstablishedHandler; +}; + +class MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge + : public MTRCallbackBridge +{ +public: + MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler) : + MTRCallbackBridge(queue, handler, OnSuccessFn){}; + + MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge(dispatch_queue_t queue, ResponseHandler handler, + MTRActionBlock action) : + MTRCallbackBridge(queue, handler, action, OnSuccessFn){}; + + static void OnSuccessFn(void * context, + const chip::app::DataModel::Nullable & value); +}; + +class MTRNullableFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge + : public MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge +{ +public: + MTRNullableFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge( + dispatch_queue_t queue, ResponseHandler handler, MTRActionBlock action, + MTRSubscriptionEstablishedHandler establishedHandler) : + MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge(queue, handler, action), + mEstablishedHandler(establishedHandler) + {} + + void OnSubscriptionEstablished(); + using MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge::KeepAliveOnCallback; + using MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge::OnDone; + +private: + MTRSubscriptionEstablishedHandler mEstablishedHandler; +}; + class MTRFanControlClusterFanModeSequenceTypeAttributeCallbackBridge : public MTRCallbackBridge { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.mm index 2dd1e11290d64c..c599975a2f40d2 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCallbackBridge.mm @@ -17525,6 +17525,106 @@ } } +void MTRFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::OnSuccessFn( + void * context, chip::app::Clusters::FanControl::AirflowDirectionEnum value) +{ + NSNumber * _Nonnull objCValue; + objCValue = [NSNumber numberWithUnsignedChar:chip::to_underlying(value)]; + DispatchSuccess(context, objCValue); +}; + +void MTRFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge::OnSubscriptionEstablished() +{ + if (!mQueue) { + return; + } + + if (mEstablishedHandler != nil) { + dispatch_async(mQueue, mEstablishedHandler); + // On failure, mEstablishedHandler will be cleaned up by our destructor, + // but we can clean it up earlier on successful subscription + // establishment. + mEstablishedHandler = nil; + } +} + +void MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackBridge::OnSuccessFn( + void * context, const chip::app::DataModel::Nullable & value) +{ + NSNumber * _Nullable objCValue; + if (value.IsNull()) { + objCValue = nil; + } else { + objCValue = [NSNumber numberWithUnsignedChar:chip::to_underlying(value.Value())]; + } + DispatchSuccess(context, objCValue); +}; + +void MTRNullableFanControlClusterAirflowDirectionEnumAttributeCallbackSubscriptionBridge::OnSubscriptionEstablished() +{ + if (!mQueue) { + return; + } + + if (mEstablishedHandler != nil) { + dispatch_async(mQueue, mEstablishedHandler); + // On failure, mEstablishedHandler will be cleaned up by our destructor, + // but we can clean it up earlier on successful subscription + // establishment. + mEstablishedHandler = nil; + } +} + +void MTRFanControlClusterDirectionEnumAttributeCallbackBridge::OnSuccessFn( + void * context, chip::app::Clusters::FanControl::DirectionEnum value) +{ + NSNumber * _Nonnull objCValue; + objCValue = [NSNumber numberWithUnsignedChar:chip::to_underlying(value)]; + DispatchSuccess(context, objCValue); +}; + +void MTRFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge::OnSubscriptionEstablished() +{ + if (!mQueue) { + return; + } + + if (mEstablishedHandler != nil) { + dispatch_async(mQueue, mEstablishedHandler); + // On failure, mEstablishedHandler will be cleaned up by our destructor, + // but we can clean it up earlier on successful subscription + // establishment. + mEstablishedHandler = nil; + } +} + +void MTRNullableFanControlClusterDirectionEnumAttributeCallbackBridge::OnSuccessFn( + void * context, const chip::app::DataModel::Nullable & value) +{ + NSNumber * _Nullable objCValue; + if (value.IsNull()) { + objCValue = nil; + } else { + objCValue = [NSNumber numberWithUnsignedChar:chip::to_underlying(value.Value())]; + } + DispatchSuccess(context, objCValue); +}; + +void MTRNullableFanControlClusterDirectionEnumAttributeCallbackSubscriptionBridge::OnSubscriptionEstablished() +{ + if (!mQueue) { + return; + } + + if (mEstablishedHandler != nil) { + dispatch_async(mQueue, mEstablishedHandler); + // On failure, mEstablishedHandler will be cleaned up by our destructor, + // but we can clean it up earlier on successful subscription + // establishment. + mEstablishedHandler = nil; + } +} + void MTRFanControlClusterFanModeSequenceTypeAttributeCallbackBridge::OnSuccessFn( void * context, chip::app::Clusters::FanControl::FanModeSequenceType value) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 03490e7005d0de..f5b2918774d2b4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -4832,6 +4832,7 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { = 0x00000009, MTRAttributeIDTypeClusterFanControlAttributeWindSettingID API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000000A, + MTRAttributeIDTypeClusterFanControlAttributeAirflowDirectionID MTR_NEWLY_AVAILABLE = 0x0000000B, MTRAttributeIDTypeClusterFanControlAttributeGeneratedCommandListID API_AVAILABLE( ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, @@ -8965,6 +8966,11 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterThermostatCommandClearWeeklyScheduleID API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000003, + // Cluster FanControl deprecated command id names + + // Cluster FanControl commands + MTRCommandIDTypeClusterFanControlCommandStepID MTR_NEWLY_AVAILABLE = 0x00000000, + // Cluster ColorControl deprecated command id names MTRClusterColorControlCommandMoveToHueID MTR_DEPRECATED("Please use MTRCommandIDTypeClusterColorControlCommandMoveToHueID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 9d1d401fe294aa..0b88662be7091f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -3874,6 +3874,11 @@ API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) queue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params + expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries + expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs + completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; + - (NSDictionary *)readAttributeFanModeWithParams:(MTRReadParams * _Nullable)params API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); - (void)writeAttributeFanModeWithValue:(NSDictionary *)dataValueDictionary @@ -3949,6 +3954,13 @@ API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) params:(MTRWriteParams * _Nullable)params API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); +- (NSDictionary *)readAttributeAirflowDirectionWithParams:(MTRReadParams * _Nullable)params MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary + expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary + expectedValueInterval:(NSNumber *)expectedValueIntervalMs + params:(MTRWriteParams * _Nullable)params MTR_NEWLY_AVAILABLE; + - (NSDictionary *)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index e13f27f1464c38..dfa3a780bce6e8 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -17934,6 +17934,77 @@ - (instancetype)initWithDevice:(MTRDevice *)device endpointID:(NSNumber *)endpoi return self; } +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params + expectedValues:(NSArray *> *)expectedValues + expectedValueInterval:(NSNumber *)expectedValueIntervalMs + completion:(MTRStatusCompletion)completion +{ + NSString * logPrefix = + [NSString stringWithFormat:@"MTRDevice command %u %u %u %u", self.device.deviceController.fabricIndex, _endpoint, + (unsigned int) MTRClusterIDTypeFanControlID, (unsigned int) MTRCommandIDTypeClusterFanControlCommandStepID]; + // Make a copy of params before we go async. + params = [params copy]; + NSNumber * timedInvokeTimeoutMsParam = params.timedInvokeTimeoutMs; + if (timedInvokeTimeoutMsParam) { + timedInvokeTimeoutMsParam = MTRClampedNumber(timedInvokeTimeoutMsParam, @(1), @(UINT16_MAX)); + } + MTRAsyncCallbackQueueWorkItem * workItem = [[MTRAsyncCallbackQueueWorkItem alloc] initWithQueue:self.device.queue]; + MTRAsyncCallbackReadyHandler readyHandler = ^(MTRDevice * device, NSUInteger retryCount) { + MTRClustersLogDequeue(logPrefix, self.device.asyncCallbackWorkQueue); + MTRBaseDevice * baseDevice = [[MTRBaseDevice alloc] initWithNodeID:self.device.nodeID + controller:self.device.deviceController]; + auto * bridge = new MTRCommandSuccessCallbackBridge( + self.device.queue, + ^(id _Nullable value, NSError * _Nullable error) { + MTRClustersLogCompletion(logPrefix, value, error); + dispatch_async(self.callbackQueue, ^{ + completion(error); + }); + [workItem endWork]; + }, + ^(ExchangeManager & exchangeManager, const SessionHandle & session, CommandSuccessCallbackType successCb, + MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) { + auto * typedBridge = static_cast(bridge); + Optional timedInvokeTimeoutMs; + Optional invokeTimeout; + ListFreer listFreer; + FanControl::Commands::Step::Type request; + if (timedInvokeTimeoutMsParam != nil) { + timedInvokeTimeoutMs.SetValue(timedInvokeTimeoutMsParam.unsignedShortValue); + } + if (params != nil) { + if (params.serverSideProcessingTimeout != nil) { + // Clamp to a number of seconds that will not overflow 32-bit + // int when converted to ms. + auto * serverSideProcessingTimeout + = MTRClampedNumber(params.serverSideProcessingTimeout, @(0), @(UINT16_MAX)); + invokeTimeout.SetValue(Seconds16(serverSideProcessingTimeout.unsignedShortValue)); + } + } + request.direction + = static_cast>(params.direction.unsignedCharValue); + request.wrap = params.wrap.boolValue; + request.lowestOff = params.lowestOff.boolValue; + + return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, + self->_endpoint, timedInvokeTimeoutMs, invokeTimeout); + }); + std::move(*bridge).DispatchAction(baseDevice); + }; + workItem.readyHandler = readyHandler; + MTRClustersLogEnqueue(logPrefix, self.device.asyncCallbackWorkQueue); + [self.device.asyncCallbackWorkQueue enqueueWorkItem:workItem]; + + if (!expectedValueIntervalMs || ([expectedValueIntervalMs compare:@(0)] == NSOrderedAscending)) { + expectedValues = nil; + } else { + expectedValueIntervalMs = MTRClampedNumber(expectedValueIntervalMs, @(1), @(UINT32_MAX)); + } + if (expectedValues) { + [self.device setExpectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs]; + } +} + - (NSDictionary *)readAttributeFanModeWithParams:(MTRReadParams * _Nullable)params { return [self.device readAttributeWithEndpointID:@(_endpoint) @@ -18136,6 +18207,33 @@ - (void)writeAttributeWindSettingWithValue:(NSDictionary *)dataV timedWriteTimeout:timedWriteTimeout]; } +- (NSDictionary *)readAttributeAirflowDirectionWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:@(_endpoint) + clusterID:@(MTRClusterIDTypeFanControlID) + attributeID:@(MTRAttributeIDTypeClusterFanControlAttributeAirflowDirectionID) + params:params]; +} + +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary + expectedValueInterval:(NSNumber *)expectedValueIntervalMs +{ + [self writeAttributeAirflowDirectionWithValue:dataValueDictionary expectedValueInterval:expectedValueIntervalMs params:nil]; +} +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary + expectedValueInterval:(NSNumber *)expectedValueIntervalMs + params:(MTRWriteParams * _Nullable)params +{ + NSNumber * timedWriteTimeout = params.timedWriteTimeout; + + [self.device writeAttributeWithEndpointID:@(_endpoint) + clusterID:@(MTRClusterIDTypeFanControlID) + attributeID:@(MTRAttributeIDTypeClusterFanControlAttributeAirflowDirectionID) + value:dataValueDictionary + expectedValueInterval:expectedValueIntervalMs + timedWriteTimeout:timedWriteTimeout]; +} + - (NSDictionary *)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params { return [self.device readAttributeWithEndpointID:@(_endpoint) @@ -18185,6 +18283,16 @@ - (instancetype)initWithDevice:(MTRDevice *)device endpoint:(uint16_t)endpoint q return [self initWithDevice:device endpointID:@(endpoint) queue:queue]; } +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params + expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries + expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs + completionHandler:(MTRStatusCompletion)completionHandler +{ + [self stepWithParams:params + expectedValues:expectedDataValueDictionaries + expectedValueInterval:expectedValueIntervalMs + completion:completionHandler]; +} @end @implementation MTRClusterThermostatUserInterfaceConfiguration diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 2e257f43660372..e0e5cf78a436f5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -4951,6 +4951,40 @@ API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; @end +MTR_NEWLY_AVAILABLE +@interface MTRFanControlClusterStepParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull direction MTR_NEWLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull wrap MTR_NEWLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nonnull lowestOff MTR_NEWLY_AVAILABLE; +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRColorControlClusterMoveToHueParams : NSObject diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index b0a66d4e6484ee..9e08be9c519993 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -5854,6 +5854,43 @@ - (NSString *)description return descriptionString; } +@end +@implementation MTRFanControlClusterStepParams +- (instancetype)init +{ + if (self = [super init]) { + + _direction = @(0); + + _wrap = @(0); + + _lowestOff = @(0); + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRFanControlClusterStepParams alloc] init]; + + other.direction = self.direction; + other.wrap = self.wrap; + other.lowestOff = self.lowestOff; + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: direction:%@; wrap:%@; lowestOff:%@; >", + NSStringFromClass([self class]), _direction, _wrap, _lowestOff]; + return descriptionString; +} + @end @implementation MTRColorControlClusterMoveToHueParams - (instancetype)init diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index ebd102aded5e53..0937581d93b5c3 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -17382,6 +17382,37 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) } // namespace WindSetting +namespace AirflowDirection { + +EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::FanControl::AirflowDirectionEnum * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::FanControl::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + *value = Traits::StorageToWorking(temp); + return status; +} +EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::FanControl::AirflowDirectionEnum value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::FanControl::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); +} + +} // namespace AirflowDirection + namespace FeatureMap { EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 510d8bd4cc582b..43ec437deca680 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -2956,6 +2956,11 @@ EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // bitmap8 EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); } // namespace WindSetting +namespace AirflowDirection { +EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::FanControl::AirflowDirectionEnum * value); // AirflowDirectionEnum +EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::FanControl::AirflowDirectionEnum value); +} // namespace AirflowDirection + namespace FeatureMap { EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index f28ebdafecf988..66585e7f5d6753 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -6812,6 +6812,12 @@ bool emberAfThermostatClusterGetWeeklyScheduleCallback( bool emberAfThermostatClusterClearWeeklyScheduleCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::Thermostat::Commands::ClearWeeklySchedule::DecodableType & commandData); +/** + * @brief Fan Control Cluster Step Command callback (from client) + */ +bool emberAfFanControlClusterStepCallback(chip::app::CommandHandler * commandObj, + const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::FanControl::Commands::Step::DecodableType & commandData); /** * @brief Color Control Cluster MoveToHue Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index d401935344cecb..a14a44bb3e875b 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -1646,6 +1646,30 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(Thermostat::ThermostatS } } +static auto __attribute__((unused)) EnsureKnownEnumValue(FanControl::AirflowDirectionEnum val) +{ + using EnumType = FanControl::AirflowDirectionEnum; + switch (val) + { + case EnumType::kForward: + case EnumType::kReverse: + return val; + default: + return static_cast(2); + } +} +static auto __attribute__((unused)) EnsureKnownEnumValue(FanControl::DirectionEnum val) +{ + using EnumType = FanControl::DirectionEnum; + switch (val) + { + case EnumType::kIncrease: + case EnumType::kDecrease: + return val; + default: + return static_cast(2); + } +} static auto __attribute__((unused)) EnsureKnownEnumValue(FanControl::FanModeSequenceType val) { using EnumType = FanControl::FanModeSequenceType; diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index d9f35548eedd69..5a5c8b48023f32 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -2143,6 +2143,30 @@ enum class ThermostatFeature : uint32_t namespace FanControl { +// Enum for AirflowDirectionEnum +enum class AirflowDirectionEnum : uint8_t +{ + kForward = 0x00, + kReverse = 0x01, + // All received enum values that are not listed above will be mapped + // to kUnknownEnumValue. This is a helper enum value that should only + // be used by code to process how it handles receiving and unknown + // enum value. This specific should never be transmitted. + kUnknownEnumValue = 2, +}; + +// Enum for DirectionEnum +enum class DirectionEnum : uint8_t +{ + kIncrease = 0x00, + kDecrease = 0x01, + // All received enum values that are not listed above will be mapped + // to kUnknownEnumValue. This is a helper enum value that should only + // be used by code to process how it handles receiving and unknown + // enum value. This specific should never be transmitted. + kUnknownEnumValue = 2, +}; + // Enum for FanModeSequenceType enum class FanModeSequenceType : uint8_t { @@ -2179,10 +2203,12 @@ enum class FanModeType : uint8_t // Bitmap for FanControlFeature enum class FanControlFeature : uint32_t { - kMultiSpeed = 0x1, - kAuto = 0x2, - kRocking = 0x4, - kWind = 0x8, + kMultiSpeed = 0x1, + kAuto = 0x2, + kRocking = 0x4, + kWind = 0x8, + kStep = 0x10, + kAirflowDirection = 0x20, }; // Bitmap for RockSupportMask diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index a37e57cacbc576..69768152eb25e1 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -13750,7 +13750,53 @@ namespace Events {} // namespace Events } // namespace Thermostat namespace FanControl { -namespace Commands {} // namespace Commands +namespace Commands { +namespace Step { +CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(Fields::kDirection), direction)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(Fields::kWrap), wrap)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(Fields::kLowestOff), lowestOff)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType outer; + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + if (!TLV::IsContextTag(reader.GetTag())) + { + continue; + } + switch (TLV::TagNumFromTag(reader.GetTag())) + { + case to_underlying(Fields::kDirection): + ReturnErrorOnFailure(DataModel::Decode(reader, direction)); + break; + case to_underlying(Fields::kWrap): + ReturnErrorOnFailure(DataModel::Decode(reader, wrap)); + break; + case to_underlying(Fields::kLowestOff): + ReturnErrorOnFailure(DataModel::Decode(reader, lowestOff)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + return CHIP_NO_ERROR; +} +} // namespace Step. +} // namespace Commands namespace Attributes { CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path) @@ -13790,6 +13836,9 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre case Attributes::WindSetting::TypeInfo::GetAttributeId(): ReturnErrorOnFailure(DataModel::Decode(reader, windSetting)); break; + case Attributes::AirflowDirection::TypeInfo::GetAttributeId(): + ReturnErrorOnFailure(DataModel::Decode(reader, airflowDirection)); + break; case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): ReturnErrorOnFailure(DataModel::Decode(reader, generatedCommandList)); break; @@ -21672,6 +21721,13 @@ bool CommandIsFabricScoped(ClusterId aCluster, CommandId aCommand) return false; } } + case Clusters::FanControl::Id: { + switch (aCommand) + { + default: + return false; + } + } case Clusters::ColorControl::Id: { switch (aCommand) { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 076c4097b13647..98b2b5c305bb33 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -17849,6 +17849,57 @@ struct TypeInfo } // namespace Thermostat namespace FanControl { +namespace Commands { +// Forward-declarations so we can reference these later. + +namespace Step { +struct Type; +struct DecodableType; +} // namespace Step + +} // namespace Commands + +namespace Commands { +namespace Step { +enum class Fields : uint8_t +{ + kDirection = 0, + kWrap = 1, + kLowestOff = 2, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::Step::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::FanControl::Id; } + + DirectionEnum direction = static_cast(0); + bool wrap = static_cast(0); + bool lowestOff = static_cast(0); + + CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::Step::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::FanControl::Id; } + + DirectionEnum direction = static_cast(0); + bool wrap = static_cast(0); + bool lowestOff = static_cast(0); + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace Step +} // namespace Commands + namespace Attributes { namespace FanMode { @@ -17983,6 +18034,18 @@ struct TypeInfo static constexpr bool MustUseTimedWrite() { return false; } }; } // namespace WindSetting +namespace AirflowDirection { +struct TypeInfo +{ + using Type = chip::app::Clusters::FanControl::AirflowDirectionEnum; + using DecodableType = chip::app::Clusters::FanControl::AirflowDirectionEnum; + using DecodableArgType = chip::app::Clusters::FanControl::AirflowDirectionEnum; + + static constexpr ClusterId GetClusterId() { return Clusters::FanControl::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::AirflowDirection::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace AirflowDirection namespace GeneratedCommandList { struct TypeInfo : public Clusters::Globals::Attributes::GeneratedCommandList::TypeInfo { @@ -18040,6 +18103,8 @@ struct TypeInfo Attributes::RockSetting::TypeInfo::DecodableType rockSetting = static_cast(0); Attributes::WindSupport::TypeInfo::DecodableType windSupport = static_cast(0); Attributes::WindSetting::TypeInfo::DecodableType windSetting = static_cast(0); + Attributes::AirflowDirection::TypeInfo::DecodableType airflowDirection = + static_cast(0); Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; Attributes::EventList::TypeInfo::DecodableType eventList; diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 62102d5fed1e5f..791d41e0187c20 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -3142,6 +3142,10 @@ namespace WindSetting { static constexpr AttributeId Id = 0x0000000A; } // namespace WindSetting +namespace AirflowDirection { +static constexpr AttributeId Id = 0x0000000B; +} // namespace AirflowDirection + namespace GeneratedCommandList { static constexpr AttributeId Id = Globals::Attributes::GeneratedCommandList::Id; } // namespace GeneratedCommandList diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index 4bf91f56d5eab0..65049b75f0c71a 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -775,6 +775,16 @@ static constexpr CommandId Id = 0x00000003; } // namespace Commands } // namespace Thermostat +namespace FanControl { +namespace Commands { + +namespace Step { +static constexpr CommandId Id = 0x00000000; +} // namespace Step + +} // namespace Commands +} // namespace FanControl + namespace ColorControl { namespace Commands { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 98e822796ecc4a..577c622ce53479 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -5024,6 +5024,7 @@ class ThermostatClearWeeklySchedule : public ClusterCommand | Cluster FanControl | 0x0202 | |------------------------------------------------------------------------------| | Commands: | | +| * Step | 0x00 | |------------------------------------------------------------------------------| | Attributes: | | | * FanMode | 0x0000 | @@ -5037,6 +5038,7 @@ class ThermostatClearWeeklySchedule : public ClusterCommand | * RockSetting | 0x0008 | | * WindSupport | 0x0009 | | * WindSetting | 0x000A | +| * AirflowDirection | 0x000B | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -5047,6 +5049,38 @@ class ThermostatClearWeeklySchedule : public ClusterCommand | Events: | | \*----------------------------------------------------------------------------*/ +/* + * Command Step + */ +class FanControlStep : public ClusterCommand +{ +public: + FanControlStep(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("step", credsIssuerConfig) + { + AddArgument("Direction", 0, UINT8_MAX, &mRequest.direction); + AddArgument("Wrap", 0, 1, &mRequest.wrap); + AddArgument("LowestOff", 0, 1, &mRequest.lowestOff); + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) command (0x00000000) on endpoint %u", endpointIds.at(0)); + + return ClusterCommand::SendCommand(device, endpointIds.at(0), 0x00000202, 0x00000000, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) command (0x00000000) on Group %u", groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, 0x00000202, 0x00000000, mRequest); + } + +private: + chip::app::Clusters::FanControl::Commands::Step::Type mRequest; +}; + /*----------------------------------------------------------------------------*\ | Cluster ThermostatUserInterfaceConfiguration | 0x0204 | |------------------------------------------------------------------------------| @@ -12974,6 +13008,7 @@ void registerClusterFanControl(Commands & commands, CredentialIssuerCommands * c // Commands // make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // // // Attributes // @@ -12989,6 +13024,7 @@ void registerClusterFanControl(Commands & commands, CredentialIssuerCommands * c make_unique(Id, "rock-setting", Attributes::RockSetting::Id, credsIssuerConfig), // make_unique(Id, "wind-support", Attributes::WindSupport::Id, credsIssuerConfig), // make_unique(Id, "wind-setting", Attributes::WindSetting::Id, credsIssuerConfig), // + make_unique(Id, "airflow-direction", Attributes::AirflowDirection::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // @@ -13018,6 +13054,9 @@ void registerClusterFanControl(Commands & commands, CredentialIssuerCommands * c WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>(Id, "wind-setting", 0, UINT8_MAX, Attributes::WindSetting::Id, WriteCommandType::kWrite, credsIssuerConfig), // + make_unique>( + Id, "airflow-direction", 0, UINT8_MAX, Attributes::AirflowDirection::Id, WriteCommandType::kWrite, + credsIssuerConfig), // make_unique>>( Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -13043,6 +13082,7 @@ void registerClusterFanControl(Commands & commands, CredentialIssuerCommands * c make_unique(Id, "rock-setting", Attributes::RockSetting::Id, credsIssuerConfig), // make_unique(Id, "wind-support", Attributes::WindSupport::Id, credsIssuerConfig), // make_unique(Id, "wind-setting", Attributes::WindSetting::Id, credsIssuerConfig), // + make_unique(Id, "airflow-direction", Attributes::AirflowDirection::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index e85d4920b846c2..87c61231d2d9be 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -7891,6 +7891,11 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("WindSetting", 1, value); } + case FanControl::Attributes::AirflowDirection::Id: { + chip::app::Clusters::FanControl::AirflowDirectionEnum value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AirflowDirection", 1, value); + } case FanControl::Attributes::GeneratedCommandList::Id: { chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 3c52df46823049..32a8c8d8967dd6 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -53231,6 +53231,7 @@ class SubscribeAttributeThermostatClusterRevision : public SubscribeAttribute { | Cluster FanControl | 0x0202 | |------------------------------------------------------------------------------| | Commands: | | +| * Step | 0x00 | |------------------------------------------------------------------------------| | Attributes: | | | * FanMode | 0x0000 | @@ -53244,6 +53245,7 @@ class SubscribeAttributeThermostatClusterRevision : public SubscribeAttribute { | * RockSetting | 0x0008 | | * WindSupport | 0x0009 | | * WindSetting | 0x000A | +| * AirflowDirection | 0x000B | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -53254,6 +53256,56 @@ class SubscribeAttributeThermostatClusterRevision : public SubscribeAttribute { | Events: | | \*----------------------------------------------------------------------------*/ +/* + * Command Step + */ +class FanControlStep : public ClusterCommand { +public: + FanControlStep() + : ClusterCommand("step") + { + AddArgument("Direction", 0, UINT8_MAX, &mRequest.direction); + AddArgument("Wrap", 0, 1, &mRequest.wrap); + AddArgument("LowestOff", 0, 1, &mRequest.lowestOff); + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) command (0x00000000) on endpoint %u", endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device + endpointID:@(endpointId) + queue:callbackQueue]; + __auto_type * params = [[MTRFanControlClusterStepParams alloc] init]; + params.timedInvokeTimeoutMs + = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; + params.direction = [NSNumber numberWithUnsignedChar:chip::to_underlying(mRequest.direction)]; + params.wrap = [NSNumber numberWithBool:mRequest.wrap]; + params.lowestOff = [NSNumber numberWithBool:mRequest.lowestOff]; + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster stepWithParams:params + completion:^(NSError * _Nullable error) { + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: + chip::app::Clusters::FanControl::Commands::Step::Type mRequest; +}; + /* * Attribute FanMode */ @@ -54264,6 +54316,116 @@ class SubscribeAttributeFanControlWindSetting : public SubscribeAttribute { } }; +/* + * Attribute AirflowDirection + */ +class ReadFanControlAirflowDirection : public ReadAttribute { +public: + ReadFanControlAirflowDirection() + : ReadAttribute("airflow-direction") + { + } + + ~ReadFanControlAirflowDirection() {} + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) ReadAttribute (0x0000000B) on endpoint %u", endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device + endpointID:@(endpointId) + queue:callbackQueue]; + [cluster readAttributeAirflowDirectionWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"FanControl.AirflowDirection response %@", [value description]); + if (error != nil) { + LogNSError("FanControl AirflowDirection read Error", error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class WriteFanControlAirflowDirection : public WriteAttribute { +public: + WriteFanControlAirflowDirection() + : WriteAttribute("airflow-direction") + { + AddArgument("attr-name", "airflow-direction"); + AddArgument("attr-value", 0, UINT8_MAX, &mValue); + WriteAttribute::AddArguments(); + } + + ~WriteFanControlAirflowDirection() {} + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) WriteAttribute (0x0000000B) on endpoint %u", endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device + endpointID:@(endpointId) + queue:callbackQueue]; + __auto_type * params = [[MTRWriteParams alloc] init]; + params.timedWriteTimeout + = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; + params.dataVersion = mDataVersion.HasValue() ? [NSNumber numberWithUnsignedInt:mDataVersion.Value()] : nil; + NSNumber * _Nonnull value = [NSNumber numberWithUnsignedChar:mValue]; + + [cluster writeAttributeAirflowDirectionWithValue:value + params:params + completion:^(NSError * _Nullable error) { + if (error != nil) { + LogNSError("FanControl AirflowDirection write Error", error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } + +private: + uint8_t mValue; +}; + +class SubscribeAttributeFanControlAirflowDirection : public SubscribeAttribute { +public: + SubscribeAttributeFanControlAirflowDirection() + : SubscribeAttribute("airflow-direction") + { + } + + ~SubscribeAttributeFanControlAirflowDirection() {} + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + ChipLogProgress(chipTool, "Sending cluster (0x00000202) ReportAttribute (0x0000000B) on endpoint %u", endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device + endpointID:@(endpointId) + queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAirflowDirectionWithParams:params + subscriptionEstablished:^() { + mSubscriptionEstablished = YES; + } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"FanControl.AirflowDirection response %@", [value description]); + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + /* * Attribute GeneratedCommandList */ @@ -99600,6 +99762,7 @@ void registerClusterFanControl(Commands & commands) commands_list clusterCommands = { make_unique(Id), // + make_unique(), // make_unique(Id), // make_unique(), // make_unique(Id), // @@ -99631,6 +99794,9 @@ void registerClusterFanControl(Commands & commands) make_unique(), // make_unique(), // make_unique(), // + make_unique(), // + make_unique(), // + make_unique(), // make_unique(), // make_unique(), // make_unique(), // From 71ea59b8e7dd88059ae4997e94e7edaba99e9ed4 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Fri, 28 Apr 2023 14:54:22 +0100 Subject: [PATCH 3/8] Ensured status was always initialised before returning, added missing break in switch case --- src/app/clusters/fan-control-server/fan-control-server.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/clusters/fan-control-server/fan-control-server.cpp b/src/app/clusters/fan-control-server/fan-control-server.cpp index 5a524179073007..71c3342f5a871f 100644 --- a/src/app/clusters/fan-control-server/fan-control-server.cpp +++ b/src/app/clusters/fan-control-server/fan-control-server.cpp @@ -136,6 +136,10 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute } res = Status::Success; } + else + { + res = Status::Success; + } break; } case SpeedSetting::Id: { @@ -384,6 +388,7 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", status)); } } + break; } default: break; From e810b6196a9ce5ffd024697c6b8aba8fef9eef2c Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Tue, 2 May 2023 10:10:05 +0100 Subject: [PATCH 4/8] Update optional parameters of Step command and matched spec naming. Improved checking on Auto feature when receiving smart mode. --- .../all-clusters-common/all-clusters-app.matter | 4 ++-- .../devices/rootnode_thermostat_bm3fb8dhYi.matter | 4 ++-- .../fan-control-server/fan-control-server.cpp | 5 +++-- .../zcl/data-model/chip/fan-control-cluster.xml | 6 +++--- src/controller/data_model/controller-clusters.matter | 4 ++-- src/controller/python/chip/clusters/Objects.py | 8 ++++---- .../Framework/CHIP/zap-generated/MTRBaseClusters.mm | 10 ++++++++-- .../Framework/CHIP/zap-generated/MTRClusters.mm | 10 ++++++++-- .../CHIP/zap-generated/MTRCommandPayloadsObjc.h | 4 ++-- .../CHIP/zap-generated/MTRCommandPayloadsObjc.mm | 4 ++-- .../app-common/zap-generated/cluster-objects.h | 8 ++++---- .../zap-generated/cluster/Commands.h | 12 ++++++++++-- 12 files changed, 50 insertions(+), 29 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 7813a956563148..1b40ea92fed987 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -3233,8 +3233,8 @@ server cluster FanControl = 514 { request struct StepRequest { DirectionEnum direction = 0; - boolean wrap = 1; - boolean lowestOff = 2; + optional boolean wrap = 1; + optional boolean lowestOff = 2; } command Step(StepRequest): DefaultSuccess = 0; diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index bbf017e8644431..85a9642ce3486c 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1333,8 +1333,8 @@ client cluster FanControl = 514 { request struct StepRequest { DirectionEnum direction = 0; - boolean wrap = 1; - boolean lowestOff = 2; + optional boolean wrap = 1; + optional boolean lowestOff = 2; } /** The Step command speeds up or slows down the fan, in steps. */ diff --git a/src/app/clusters/fan-control-server/fan-control-server.cpp b/src/app/clusters/fan-control-server/fan-control-server.cpp index 71c3342f5a871f..66f9f2e4bde4ec 100644 --- a/src/app/clusters/fan-control-server/fan-control-server.cpp +++ b/src/app/clusters/fan-control-server/fan-control-server.cpp @@ -125,8 +125,9 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute { FanModeSequenceType fanModeSequence; FanModeSequence::Get(attributePath.mEndpointId, &fanModeSequence); - if ((fanModeSequence == FanModeSequenceType::kOffLowHighAuto) || - (fanModeSequence == FanModeSequenceType::kOffLowMedHighAuto)) + if (SupportsAuto(attributePath.mEndpointId) && + ((fanModeSequence == FanModeSequenceType::kOffLowHighAuto) || + (fanModeSequence == FanModeSequenceType::kOffLowMedHighAuto))) { *value = static_cast(FanModeType::kAuto); } diff --git a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml index e3f4616fb9c5a7..3114a7fe6ad764 100644 --- a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml @@ -24,7 +24,7 @@ limitations under the License. - + @@ -105,8 +105,8 @@ limitations under the License. The Step command speeds up or slows down the fan, in steps. - - + + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index ac37305df61133..c44af1e6bbc46b 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -3603,8 +3603,8 @@ client cluster FanControl = 514 { request struct StepRequest { DirectionEnum direction = 0; - boolean wrap = 1; - boolean lowestOff = 2; + optional boolean wrap = 1; + optional boolean lowestOff = 2; } /** The Step command speeds up or slows down the fan, in steps. */ diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index bb1e0eae35ac70..6fa812d529f92f 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -19410,13 +19410,13 @@ def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ ClusterObjectFieldDescriptor(Label="direction", Tag=0, Type=FanControl.Enums.DirectionEnum), - ClusterObjectFieldDescriptor(Label="wrap", Tag=1, Type=bool), - ClusterObjectFieldDescriptor(Label="lowestOff", Tag=2, Type=bool), + ClusterObjectFieldDescriptor(Label="wrap", Tag=1, Type=typing.Optional[bool]), + ClusterObjectFieldDescriptor(Label="lowestOff", Tag=2, Type=typing.Optional[bool]), ]) direction: 'FanControl.Enums.DirectionEnum' = 0 - wrap: 'bool' = False - lowestOff: 'bool' = False + wrap: 'typing.Optional[bool]' = None + lowestOff: 'typing.Optional[bool]' = None class Attributes: @dataclass diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 42e7d97f74f0b0..e57d62b8b7c444 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -65228,8 +65228,14 @@ - (void)stepWithParams:(MTRFanControlClusterStepParams *)params completion:(MTRS } request.direction = static_cast>(params.direction.unsignedCharValue); - request.wrap = params.wrap.boolValue; - request.lowestOff = params.lowestOff.boolValue; + if (params.wrap != nil) { + auto & definedValue_0 = request.wrap.Emplace(); + definedValue_0 = params.wrap.boolValue; + } + if (params.lowestOff != nil) { + auto & definedValue_0 = request.lowestOff.Emplace(); + definedValue_0 = params.lowestOff.boolValue; + } return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self->_endpoint, timedInvokeTimeoutMs, invokeTimeout); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index dfa3a780bce6e8..04cde41b91184c 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -17983,8 +17983,14 @@ - (void)stepWithParams:(MTRFanControlClusterStepParams *)params } request.direction = static_cast>(params.direction.unsignedCharValue); - request.wrap = params.wrap.boolValue; - request.lowestOff = params.lowestOff.boolValue; + if (params.wrap != nil) { + auto & definedValue_0 = request.wrap.Emplace(); + definedValue_0 = params.wrap.boolValue; + } + if (params.lowestOff != nil) { + auto & definedValue_0 = request.lowestOff.Emplace(); + definedValue_0 = params.lowestOff.boolValue; + } return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self->_endpoint, timedInvokeTimeoutMs, invokeTimeout); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index e0e5cf78a436f5..4b80ac5ead44f4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -4956,9 +4956,9 @@ MTR_NEWLY_AVAILABLE @property (nonatomic, copy) NSNumber * _Nonnull direction MTR_NEWLY_AVAILABLE; -@property (nonatomic, copy) NSNumber * _Nonnull wrap MTR_NEWLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable wrap MTR_NEWLY_AVAILABLE; -@property (nonatomic, copy) NSNumber * _Nonnull lowestOff MTR_NEWLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable lowestOff MTR_NEWLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 9e08be9c519993..6f86eb17739fc7 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -5862,9 +5862,9 @@ - (instancetype)init _direction = @(0); - _wrap = @(0); + _wrap = nil; - _lowestOff = @(0); + _lowestOff = nil; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 98b2b5c305bb33..b9b5bafc6f916f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -17876,8 +17876,8 @@ struct Type static constexpr ClusterId GetClusterId() { return Clusters::FanControl::Id; } DirectionEnum direction = static_cast(0); - bool wrap = static_cast(0); - bool lowestOff = static_cast(0); + Optional wrap; + Optional lowestOff; CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) const; @@ -17893,8 +17893,8 @@ struct DecodableType static constexpr ClusterId GetClusterId() { return Clusters::FanControl::Id; } DirectionEnum direction = static_cast(0); - bool wrap = static_cast(0); - bool lowestOff = static_cast(0); + Optional wrap; + Optional lowestOff; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace Step diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 32a8c8d8967dd6..24823314af78f5 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -53282,8 +53282,16 @@ class FanControlStep : public ClusterCommand { params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; params.direction = [NSNumber numberWithUnsignedChar:chip::to_underlying(mRequest.direction)]; - params.wrap = [NSNumber numberWithBool:mRequest.wrap]; - params.lowestOff = [NSNumber numberWithBool:mRequest.lowestOff]; + if (mRequest.wrap.HasValue()) { + params.wrap = [NSNumber numberWithBool:mRequest.wrap.Value()]; + } else { + params.wrap = nil; + } + if (mRequest.lowestOff.HasValue()) { + params.lowestOff = [NSNumber numberWithBool:mRequest.lowestOff.Value()]; + } else { + params.lowestOff = nil; + } uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { From 23afe94dfb21120ada582e4264258f1939699c80 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Wed, 3 May 2023 10:39:31 +0100 Subject: [PATCH 5/8] Added a stop-gap fan-stub.cpp so that the existing FanControl tests pass for TE1 --- .../all-clusters-common/src/fan-stub.cpp | 118 ++++++++++++++++++ examples/all-clusters-app/linux/BUILD.gn | 1 + 2 files changed, 119 insertions(+) create mode 100644 examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp diff --git a/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp new file mode 100644 index 00000000000000..28440ad0957e1c --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp @@ -0,0 +1,118 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::FanControl::Attributes; + +namespace { + +/* + * TODO: This is a stop-gap solution to allow the existing fan control cluster tests to run after changes to + * the cluster objects for TE1. This should be removed once #6496 is resolved as it will likley result in a + * FanControl delegate added to the SDK. + * + * FYI... The previous implementation of the FanControl cluster set the speedCurrent/percentCurrent when it received + * speedSetting/percentSetting. The new implementation of the FanControl cluster does not do this as this should + * really be done by the application. + */ + +class FanAttrAccess : public AttributeAccessInterface +{ +public: + // Register for the FanControl cluster on all endpoints. + FanAttrAccess() : AttributeAccessInterface(Optional::Missing(), FanControl::Id) {} + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + +private: + static constexpr uint16_t ClusterRevision = 1; + + CHIP_ERROR ReadPercentCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadSpeedCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder); +}; + +CHIP_ERROR FanAttrAccess::ReadPercentCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + // Return PercentSetting attribute value for now + DataModel::Nullable percentSetting; + PercentSetting::Get(endpoint, percentSetting); + if (percentSetting.HasValidValue()) + { + return aEncoder.Encode(percentSetting.Value()); + } + else + { + return aEncoder.Encode(0); + } +} + +CHIP_ERROR FanAttrAccess::ReadSpeedCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + // Return SpeedCurrent attribute value for now + DataModel::Nullable speedSetting; + SpeedSetting::Get(endpoint, speedSetting); + if (speedSetting.HasValidValue()) + { + return aEncoder.Encode(speedSetting.Value()); + } + else + { + return aEncoder.Encode(0); + } +} + +FanAttrAccess gAttrAccess; + +CHIP_ERROR FanAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == FanControl::Id); + + switch (aPath.mAttributeId) + { + case SpeedCurrent::Id: + return ReadSpeedCurrent(aPath.mEndpointId, aEncoder); + case PercentCurrent::Id: + return ReadPercentCurrent(aPath.mEndpointId, aEncoder); + default: + break; + } + return CHIP_NO_ERROR; +} +} // anonymous namespace + +void emberAfFanControlClusterInitCallback(EndpointId endpoint) +{ + uint32_t featureMap = 0; + + featureMap |= to_underlying(FanControl::FanControlFeature::kMultiSpeed); + featureMap |= to_underlying(FanControl::FanControlFeature::kAuto); + + FeatureMap::Set(endpoint, featureMap); + + registerAttributeAccessOverride(&gAttrAccess); +} diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index 1b8ff71bc66e76..d3c9bbf679685c 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -24,6 +24,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", "AllClustersCommandDelegate.cpp", "AppOptions.cpp", "WindowCoveringManager.cpp", From 9201ad174773cdbf1e613c96c7a619a23b7e0ed1 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Wed, 3 May 2023 11:27:57 +0100 Subject: [PATCH 6/8] removed unused variable --- examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp index 28440ad0957e1c..ad6cc7195b3fbc 100644 --- a/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp @@ -50,8 +50,6 @@ class FanAttrAccess : public AttributeAccessInterface CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; private: - static constexpr uint16_t ClusterRevision = 1; - CHIP_ERROR ReadPercentCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder); CHIP_ERROR ReadSpeedCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder); }; From d23136ac412c4bc41e379fbd1a488a966c7a0b59 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Wed, 3 May 2023 13:33:37 +0100 Subject: [PATCH 7/8] fixed return after else warning --- .../all-clusters-common/src/fan-stub.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp index ad6cc7195b3fbc..4be211d6e041b0 100644 --- a/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp @@ -59,14 +59,13 @@ CHIP_ERROR FanAttrAccess::ReadPercentCurrent(EndpointId endpoint, AttributeValue // Return PercentSetting attribute value for now DataModel::Nullable percentSetting; PercentSetting::Get(endpoint, percentSetting); + uint8_t ret = 0; if (percentSetting.HasValidValue()) { - return aEncoder.Encode(percentSetting.Value()); - } - else - { - return aEncoder.Encode(0); + ret = percentSetting.Value(); } + + return aEncoder.Encode(ret); } CHIP_ERROR FanAttrAccess::ReadSpeedCurrent(EndpointId endpoint, AttributeValueEncoder & aEncoder) @@ -74,14 +73,13 @@ CHIP_ERROR FanAttrAccess::ReadSpeedCurrent(EndpointId endpoint, AttributeValueEn // Return SpeedCurrent attribute value for now DataModel::Nullable speedSetting; SpeedSetting::Get(endpoint, speedSetting); + uint8_t ret = 0; if (speedSetting.HasValidValue()) { - return aEncoder.Encode(speedSetting.Value()); - } - else - { - return aEncoder.Encode(0); + ret = speedSetting.Value(); } + + return aEncoder.Encode(ret); } FanAttrAccess gAttrAccess; From 44a7296347dec606ff20db50bec4b154c1a1d1f3 Mon Sep 17 00:00:00 2001 From: Matthew Hazley Date: Wed, 3 May 2023 13:39:26 +0100 Subject: [PATCH 8/8] reordered files as per restyler --- examples/all-clusters-app/linux/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index d3c9bbf679685c..402649c13bba05 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -23,8 +23,8 @@ source_set("chip-all-clusters-common") { sources = [ "${chip_root}/examples/all-clusters-app/all-clusters-common/src/binding-handler.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "AllClustersCommandDelegate.cpp", "AppOptions.cpp", "WindowCoveringManager.cpp",