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 e7dd2a91cfd493..946139ffd745b8 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 @@ -3203,6 +3203,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { 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 7a0673a1258820..a1c11bf2222ad3 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 @@ -2725,6 +2725,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index b57fb12677d7c9..63f51e5ea5ee6a 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -1389,6 +1389,7 @@ client cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index d3b1db26b286dc..f45c4ad63689ec 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1246,6 +1246,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index dcf760c6988109..c7a4d886fda5c1 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -2476,6 +2476,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 1b3cce593cf064..7e3ce228e46058 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -2437,6 +2437,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 55377700429ea6..6e4528e50cffd7 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -1676,6 +1676,7 @@ server cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/src/app/clusters/thermostat-server/thermostat-server.cpp b/src/app/clusters/thermostat-server/thermostat-server.cpp index 2d9585023a2a5b..85fa7c7a035322 100644 --- a/src/app/clusters/thermostat-server/thermostat-server.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server.cpp @@ -31,9 +31,13 @@ #include using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; using namespace chip::app::Clusters::Thermostat; using namespace chip::app::Clusters::Thermostat::Attributes; +using imcode = Protocols::InteractionModel::Status; + constexpr int16_t kDefaultAbsMinHeatSetpointLimit = 700; // 7C (44.5 F) is the default constexpr int16_t kDefaultAbsMaxHeatSetpointLimit = 3000; // 30C (86 F) is the default constexpr int16_t kDefaultMinHeatSetpointLimit = 700; // 7C (44.5 F) is the default @@ -62,6 +66,90 @@ constexpr int8_t kDefaultDeadBand = 25; // 2.5C is the default #define FEATURE_MAP_DEFAULT FEATURE_MAP_HEAT | FEATURE_MAP_COOL | FEATURE_MAP_AUTO +namespace { + +class ThermostatAttrAccess : public AttributeAccessInterface +{ +public: + ThermostatAttrAccess() : AttributeAccessInterface(Optional::Missing(), Thermostat::Id) {} + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override; +}; + +ThermostatAttrAccess gThermostatAttrAccess; + +CHIP_ERROR ThermostatAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Thermostat::Id); + + uint32_t ourFeatureMap; + bool localTemperatureNotExposedSupported = (FeatureMap::Get(aPath.mEndpointId, &ourFeatureMap) == EMBER_ZCL_STATUS_SUCCESS) && + ((ourFeatureMap & to_underlying(Feature::kLocalTemperatureNotExposed)) != 0); + + switch (aPath.mAttributeId) + { + case LocalTemperature::Id: + if (localTemperatureNotExposedSupported) + { + return aEncoder.EncodeNull(); + } + break; + case RemoteSensing::Id: + if (localTemperatureNotExposedSupported) + { + uint8_t valueRemoteSensing; + EmberAfStatus status = RemoteSensing::Get(aPath.mEndpointId, &valueRemoteSensing); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + StatusIB statusIB(ToInteractionModelStatus(status)); + return statusIB.ToChipError(); + } + valueRemoteSensing &= 0xFE; // clear bit 1 (LocalTemperature RemoteSensing bit) + return aEncoder.Encode(valueRemoteSensing); + } + break; + default: // return CHIP_NO_ERROR and just read from the attribute store in default + break; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) +{ + VerifyOrDie(aPath.mClusterId == Thermostat::Id); + + uint32_t ourFeatureMap; + bool localTemperatureNotExposedSupported = (FeatureMap::Get(aPath.mEndpointId, &ourFeatureMap) == EMBER_ZCL_STATUS_SUCCESS) && + ((ourFeatureMap & to_underlying(Feature::kLocalTemperatureNotExposed)) != 0); + + switch (aPath.mAttributeId) + { + case RemoteSensing::Id: + if (localTemperatureNotExposedSupported) + { + uint8_t valueRemoteSensing; + ReturnErrorOnFailure(aDecoder.Decode(valueRemoteSensing)); + if (valueRemoteSensing & 0x01) // If setting bit 1 (LocalTemperature RemoteSensing bit) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + EmberAfStatus status = RemoteSensing::Set(aPath.mEndpointId, valueRemoteSensing); + StatusIB statusIB(ToInteractionModelStatus(status)); + return statusIB.ToChipError(); + } + break; + default: // return CHIP_NO_ERROR and just write to the attribute store in default + break; + } + + return CHIP_NO_ERROR; +} + +} // anonymous namespace + void emberAfThermostatClusterServerInitCallback(chip::EndpointId endpoint) { // TODO @@ -78,8 +166,6 @@ void emberAfThermostatClusterServerInitCallback(chip::EndpointId endpoint) // or should this just be the responsibility of the thermostat application? } -using imcode = Protocols::InteractionModel::Status; - Protocols::InteractionModel::Status MatterThermostatClusterServerPreAttributeChangedCallback(const app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value) @@ -754,4 +840,7 @@ bool emberAfThermostatClusterSetpointRaiseLowerCallback(app::CommandHandler * co return true; } -void MatterThermostatPluginServerInitCallback() {} +void MatterThermostatPluginServerInitCallback() +{ + registerAttributeAccessOverride(&gThermostatAttrAccess); +} diff --git a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml index bf5e90a5ca8859..e918a0706df92b 100644 --- a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml @@ -25,6 +25,7 @@ limitations under the License. + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 67bb2c12b80092..271670f7c03ac9 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -4341,6 +4341,7 @@ client cluster Thermostat = 513 { kScheduleConfiguration = 0x8; kSetback = 0x10; kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; } bitmap ModeForSequence : BITMAP8 { diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 0a73b67b5a2131..3a9e9e0ac2656a 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -23088,6 +23088,7 @@ class Feature(IntFlag): kScheduleConfiguration = 0x8 kSetback = 0x10 kAutoMode = 0x20 + kLocalTemperatureNotExposed = 0x40 class ModeForSequence(IntFlag): kHeatSetpointPresent = 0x1 diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 1bf2eec2b9ff63..970387513955ed 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -24619,6 +24619,7 @@ typedef NS_OPTIONS(uint32_t, MTRThermostatFeature) { MTRThermostatFeatureAutomode MTR_DEPRECATED( "Please use MTRThermostatFeatureAutoMode", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) = 0x20, + MTRThermostatFeatureLocalTemperatureNotExposed MTR_NEWLY_AVAILABLE = 0x40, } API_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); typedef NS_OPTIONS(uint8_t, MTRThermostatModeForSequence) { 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 7a210a34e81055..6a6a3c7aad61e8 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 @@ -2828,12 +2828,13 @@ enum class DayOfWeek : uint8_t // Bitmap for Feature enum class Feature : uint32_t { - kHeating = 0x1, - kCooling = 0x2, - kOccupancy = 0x4, - kScheduleConfiguration = 0x8, - kSetback = 0x10, - kAutoMode = 0x20, + kHeating = 0x1, + kCooling = 0x2, + kOccupancy = 0x4, + kScheduleConfiguration = 0x8, + kSetback = 0x10, + kAutoMode = 0x20, + kLocalTemperatureNotExposed = 0x40, }; // Bitmap for ModeForSequence