Skip to content

Commit 8abb3a2

Browse files
authored
Merge branch 'master' into camera-webrtc-updates
2 parents 401826e + b20d8ae commit 8abb3a2

File tree

12 files changed

+297
-173
lines changed

12 files changed

+297
-173
lines changed

examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <app-common/zap-generated/cluster-objects.h>
2020
#include <app-common/zap-generated/ids/Attributes.h>
2121
#include <app-common/zap-generated/ids/Clusters.h>
22+
#include <app/AttributeAccessInterface.h>
2223
#include <app/AttributeAccessInterfaceRegistry.h>
2324
#include <app/clusters/fan-control-server/fan-control-server.h>
2425
#include <app/util/attribute-storage.h>
@@ -33,11 +34,13 @@ using namespace chip::app::Clusters::FanControl::Attributes;
3334
using Protocols::InteractionModel::Status;
3435

3536
namespace {
36-
class FanControlManager : public FanControlAttributeAccessInterface, public Delegate
37+
class FanControlManager : public AttributeAccessInterface, public Delegate
3738
{
3839
public:
3940
// Register for the FanControl cluster on all endpoints.
40-
FanControlManager(EndpointId aEndpointId) : FanControlAttributeAccessInterface(aEndpointId), Delegate(aEndpointId) {}
41+
FanControlManager(EndpointId aEndpointId) :
42+
AttributeAccessInterface(Optional<EndpointId>(aEndpointId), FanControl::Id), Delegate(aEndpointId)
43+
{}
4144

4245
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
4346
Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override;

examples/chef/common/chef-fan-control-manager.cpp

+224-70
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,45 @@ using namespace chip::app::Clusters::FanControl::Attributes;
3838
using Protocols::InteractionModel::Status;
3939

4040
namespace {
41-
class ChefFanControlManager : public AttributeAccessInterface, public Delegate
41+
class ChefFanControlManager : public Delegate
4242
{
4343
public:
44-
ChefFanControlManager(EndpointId aEndpointId) :
45-
AttributeAccessInterface(Optional<EndpointId>(aEndpointId), FanControl::Id), Delegate(aEndpointId)
46-
{}
44+
ChefFanControlManager(EndpointId aEndpointId) : Delegate(aEndpointId) {}
4745

48-
CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override;
49-
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
46+
void Init();
47+
void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value);
5048
Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override;
49+
DataModel::Nullable<uint8_t> GetSpeedSetting();
50+
DataModel::Nullable<Percent> GetPercentSetting();
5151

5252
private:
53-
Nullable<uint8_t> mPercentSetting{};
54-
Nullable<uint8_t> mSpeedSetting{};
53+
uint8_t mPercentCurrent = 0;
54+
uint8_t mSpeedCurrent = 0;
55+
56+
// Fan Mode Limits
57+
struct Range
58+
{
59+
bool Contains(int value) const { return value >= low && value <= high; }
60+
int Low() const { return low; }
61+
int High() const { return high; }
62+
63+
int low;
64+
int high;
65+
};
66+
static constexpr Range kFanModeLowSpeedRange = { 1, 3 };
67+
static constexpr Range kFanModeMediumSpeedRange = { 4, 7 };
68+
static constexpr Range kFanModeHighSpeedRange = { 8, 10 };
69+
70+
static_assert(kFanModeLowSpeedRange.low <= kFanModeLowSpeedRange.high);
71+
static_assert(kFanModeLowSpeedRange.high + 1 == kFanModeMediumSpeedRange.low);
72+
static_assert(kFanModeMediumSpeedRange.high + 1 == kFanModeHighSpeedRange.low);
73+
static_assert(kFanModeHighSpeedRange.low <= kFanModeHighSpeedRange.high);
74+
75+
void FanModeWriteCallback(FanControl::FanModeEnum aNewFanMode);
76+
void SetSpeedCurrent(uint8_t aNewSpeedCurrent);
77+
void SetPercentCurrent(uint8_t aNewPercentCurrent);
78+
void SetSpeedSetting(DataModel::Nullable<uint8_t> aNewSpeedSetting);
79+
static FanControl::FanModeEnum SpeedToFanMode(uint8_t speed);
5580
};
5681

5782
static std::unique_ptr<ChefFanControlManager> mFanControlManager;
@@ -99,98 +124,222 @@ Status ChefFanControlManager::HandleStep(StepDirectionEnum aDirection, bool aWra
99124
return SpeedSetting::Set(mEndpoint, newSpeedSetting);
100125
}
101126

102-
CHIP_ERROR ChefFanControlManager::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
127+
void ChefFanControlManager::HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value)
103128
{
104-
VerifyOrDie(aPath.mClusterId == FanControl::Id);
105-
VerifyOrDie(aPath.mEndpointId == mEndpoint);
106-
107-
switch (aPath.mAttributeId)
129+
ChipLogProgress(NotSpecified, "ChefFanControlManager::HandleFanControlAttributeChange");
130+
switch (attributeId)
108131
{
109-
case SpeedSetting::Id: {
110-
Nullable<uint8_t> newSpeedSetting;
111-
ReturnErrorOnFailure(aDecoder.Decode(newSpeedSetting));
112-
113-
// Ensure new speed is in bounds
132+
case FanControl::Attributes::PercentSetting::Id: {
133+
ChipLogProgress(NotSpecified, "ChefFanControlManager::HandleFanControlAttributeChange PercentSetting");
134+
DataModel::Nullable<Percent> percentSetting;
135+
if (!NumericAttributeTraits<Percent>::IsNullValue(*value))
114136
{
115-
uint8_t maxSpeedSetting = 0;
116-
Protocols::InteractionModel::Status status = SpeedMax::Get(mEndpoint, &maxSpeedSetting);
117-
VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_IM_GLOBAL_STATUS(Failure));
118-
119-
if (!newSpeedSetting.IsNull() && newSpeedSetting.Value() > maxSpeedSetting)
120-
{
121-
return CHIP_IM_GLOBAL_STATUS(ConstraintError);
122-
}
137+
percentSetting.SetNonNull(NumericAttributeTraits<Percent>::StorageToWorking(*value));
123138
}
124-
125-
// Only act on changed.
126-
if (newSpeedSetting != mSpeedSetting)
139+
else
127140
{
128-
mSpeedSetting = newSpeedSetting;
129-
130-
// Mark both the setting AND the current dirty, since the current always
131-
// tracks the target for our product.
132-
MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::SpeedSetting::Id);
133-
MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::SpeedCurrent::Id);
141+
percentSetting.SetNull();
134142
}
135143

144+
// The cluster code in fan-control-server.cpp is the only one allowed to set PercentSetting to null.
145+
// This happens as a consequence of setting the FanMode to kAuto. In auto mode, percentCurrent should continue to report the
146+
// real fan speed percentage. In this example, we set PercentCurrent to 0 here as we don't have a real value for the Fan
147+
// speed or a FanAutoMode simulator.
148+
// When not Null, SpeedCurrent tracks SpeedSetting's value.
149+
SetPercentCurrent(percentSetting.ValueOr(0));
136150
break;
137151
}
138-
case PercentSetting::Id: {
139-
Nullable<uint8_t> newPercentSetting;
140-
ReturnErrorOnFailure(aDecoder.Decode(newPercentSetting));
141152

142-
// Ensure new speed in percent is valid.
143-
if (!newPercentSetting.IsNull() && newPercentSetting.Value() > 100)
153+
case FanControl::Attributes::SpeedSetting::Id: {
154+
ChipLogProgress(NotSpecified, "ChefFanControlManager::HandleFanControlAttributeChange SpeedSetting");
155+
DataModel::Nullable<uint8_t> speedSetting;
156+
if (!NumericAttributeTraits<uint8_t>::IsNullValue(*value))
144157
{
145-
return CHIP_IM_GLOBAL_STATUS(ConstraintError);
158+
speedSetting.SetNonNull(NumericAttributeTraits<uint8_t>::StorageToWorking(*value));
146159
}
147-
148-
// Only act on changed.
149-
if (newPercentSetting != mPercentSetting)
160+
else
150161
{
151-
mPercentSetting = newPercentSetting;
152-
153-
// Mark both the setting AND the current dirty, since the current always
154-
// tracks the target for our product.
155-
MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::PercentSetting::Id);
156-
MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::PercentCurrent::Id);
162+
speedSetting.SetNull();
157163
}
158164

165+
// The cluster code in fan-control-server.cpp is the only one allowed to set speedSetting to null.
166+
// This happens as a consequence of setting the FanMode to kAuto. In auto mode, speedCurrent should continue to report the
167+
// real fan speed. In this example, we set SpeedCurrent to 0 here as we don't have a real value for the Fan speed or a
168+
// FanAutoMode simulator.
169+
// When not Null, SpeedCurrent tracks SpeedSetting's value.
170+
SetSpeedCurrent(speedSetting.ValueOr(0));
171+
// Determine if the speed change should also change the fan mode
172+
FanControl::Attributes::FanMode::Set(mEndpoint, SpeedToFanMode(mSpeedCurrent));
159173
break;
160174
}
161-
default:
175+
176+
case FanControl::Attributes::FanMode::Id: {
177+
ChipLogProgress(NotSpecified, "ChefFanControlManager::HandleFanControlAttributeChange FanMode");
178+
179+
static_assert(sizeof(FanControl::FanModeEnum) == 1);
180+
FanControl::FanModeEnum fanMode = static_cast<FanControl::FanModeEnum>(*value);
181+
FanModeWriteCallback(fanMode);
162182
break;
163183
}
164184

165-
// Fall through goes to attribute store legacy handling.
166-
return CHIP_NO_ERROR;
185+
default: {
186+
break;
187+
}
188+
}
189+
}
190+
191+
FanControl::FanModeEnum ChefFanControlManager::SpeedToFanMode(uint8_t speed)
192+
{
193+
if (speed == 0)
194+
{
195+
return FanControl::FanModeEnum::kOff;
196+
}
197+
if (kFanModeLowSpeedRange.Contains(speed))
198+
{
199+
return FanControl::FanModeEnum::kLow;
200+
}
201+
if (kFanModeMediumSpeedRange.Contains(speed))
202+
{
203+
return FanControl::FanModeEnum::kMedium;
204+
}
205+
return FanControl::FanModeEnum::kHigh;
167206
}
168207

169-
CHIP_ERROR ChefFanControlManager::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
208+
void ChefFanControlManager::SetPercentCurrent(uint8_t aNewPercentCurrent)
170209
{
171-
VerifyOrDie(aPath.mClusterId == FanControl::Id);
172-
VerifyOrDie(aPath.mEndpointId == mEndpoint);
210+
if (aNewPercentCurrent == mPercentCurrent)
211+
{
212+
return;
213+
}
173214

174-
switch (aPath.mAttributeId)
215+
ChipLogDetail(NotSpecified, "ChefFanControlManager::SetPercentCurrent: %d", aNewPercentCurrent);
216+
mPercentCurrent = aNewPercentCurrent;
217+
Status status = FanControl::Attributes::PercentCurrent::Set(mEndpoint, mPercentCurrent);
218+
if (status != Status::Success)
175219
{
176-
case PercentCurrent::Id: {
177-
// Current percents always tracks setting immediately in our implementation.
178-
return aEncoder.Encode(mPercentSetting.ValueOr(0));
220+
ChipLogError(NotSpecified, "ChefFanControlManager::SetPercentCurrent: failed to set PercentCurrent attribute: %d",
221+
to_underlying(status));
179222
}
180-
case PercentSetting::Id: {
181-
return aEncoder.Encode(mPercentSetting);
223+
}
224+
225+
void ChefFanControlManager::SetSpeedCurrent(uint8_t aNewSpeedCurrent)
226+
{
227+
if (aNewSpeedCurrent == mSpeedCurrent)
228+
{
229+
return;
182230
}
183-
case SpeedCurrent::Id: {
184-
// Current speed always tracks setting immediately in our implementation.
185-
return aEncoder.Encode(mSpeedSetting.ValueOr(0));
231+
232+
ChipLogDetail(NotSpecified, "ChefFanControlManager::SetSpeedCurrent: %d", aNewSpeedCurrent);
233+
mSpeedCurrent = aNewSpeedCurrent;
234+
Status status = FanControl::Attributes::SpeedCurrent::Set(mEndpoint, aNewSpeedCurrent);
235+
if (status != Status::Success)
236+
{
237+
ChipLogError(NotSpecified, "ChefFanControlManager::SetSpeedCurrent: failed to set SpeedCurrent attribute: %d",
238+
to_underlying(status));
186239
}
187-
case SpeedSetting::Id: {
188-
return aEncoder.Encode(mSpeedSetting);
240+
}
241+
242+
void ChefFanControlManager::FanModeWriteCallback(FanControl::FanModeEnum aNewFanMode)
243+
{
244+
ChipLogDetail(NotSpecified, "ChefFanControlManager::FanModeWriteCallback: %d", to_underlying(aNewFanMode));
245+
switch (aNewFanMode)
246+
{
247+
case FanControl::FanModeEnum::kOff: {
248+
if (mSpeedCurrent != 0)
249+
{
250+
DataModel::Nullable<uint8_t> speedSetting(0);
251+
SetSpeedSetting(speedSetting);
252+
}
253+
break;
189254
}
190-
default:
255+
case FanControl::FanModeEnum::kLow: {
256+
if (!kFanModeLowSpeedRange.Contains(mSpeedCurrent))
257+
{
258+
DataModel::Nullable<uint8_t> speedSetting(kFanModeLowSpeedRange.Low());
259+
SetSpeedSetting(speedSetting);
260+
}
191261
break;
192262
}
193-
return CHIP_NO_ERROR;
263+
case FanControl::FanModeEnum::kMedium: {
264+
if (!kFanModeMediumSpeedRange.Contains(mSpeedCurrent))
265+
{
266+
DataModel::Nullable<uint8_t> speedSetting(kFanModeMediumSpeedRange.Low());
267+
SetSpeedSetting(speedSetting);
268+
}
269+
break;
270+
}
271+
case FanControl::FanModeEnum::kOn:
272+
case FanControl::FanModeEnum::kHigh: {
273+
if (!kFanModeHighSpeedRange.Contains(mSpeedCurrent))
274+
{
275+
DataModel::Nullable<uint8_t> speedSetting(kFanModeHighSpeedRange.Low());
276+
SetSpeedSetting(speedSetting);
277+
}
278+
break;
279+
}
280+
case FanControl::FanModeEnum::kSmart:
281+
case FanControl::FanModeEnum::kAuto: {
282+
ChipLogProgress(NotSpecified, "ChefFanControlManager::FanModeWriteCallback: Auto");
283+
break;
284+
}
285+
case FanControl::FanModeEnum::kUnknownEnumValue: {
286+
ChipLogProgress(NotSpecified, "ChefFanControlManager::FanModeWriteCallback: Unknown");
287+
break;
288+
}
289+
}
290+
}
291+
292+
void ChefFanControlManager::SetSpeedSetting(DataModel::Nullable<uint8_t> aNewSpeedSetting)
293+
{
294+
if (aNewSpeedSetting.IsNull())
295+
{
296+
ChipLogError(NotSpecified, "ChefFanControlManager::SetSpeedSetting: null value is invalid");
297+
return;
298+
}
299+
300+
if (aNewSpeedSetting.Value() != mSpeedCurrent)
301+
{
302+
Status status = FanControl::Attributes::SpeedSetting::Set(mEndpoint, aNewSpeedSetting);
303+
if (status != Status::Success)
304+
{
305+
ChipLogError(NotSpecified, "ChefFanControlManager::SetSpeedSetting: failed to set SpeedSetting attribute: %d",
306+
to_underlying(status));
307+
}
308+
}
309+
}
310+
311+
void ChefFanControlManager::Init()
312+
{
313+
SetPercentCurrent(GetPercentSetting().ValueOr(0));
314+
SetSpeedCurrent(GetSpeedSetting().ValueOr(0));
315+
}
316+
317+
DataModel::Nullable<Percent> ChefFanControlManager::GetPercentSetting()
318+
{
319+
DataModel::Nullable<Percent> percentSetting;
320+
Status status = FanControl::Attributes::PercentSetting::Get(mEndpoint, percentSetting);
321+
322+
if (status != Status::Success)
323+
{
324+
ChipLogError(NotSpecified, "ChefFanControlManager::GetPercentSetting: failed to get PercentSetting attribute: %d",
325+
to_underlying(status));
326+
}
327+
328+
return percentSetting;
329+
}
330+
331+
DataModel::Nullable<uint8_t> ChefFanControlManager::GetSpeedSetting()
332+
{
333+
DataModel::Nullable<uint8_t> speedSetting;
334+
Status status = FanControl::Attributes::SpeedSetting::Get(mEndpoint, speedSetting);
335+
336+
if (status != Status::Success)
337+
{
338+
ChipLogError(NotSpecified, "ChefFanControlManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d",
339+
to_underlying(status));
340+
}
341+
342+
return speedSetting;
194343
}
195344

196345
} // anonymous namespace
@@ -199,6 +348,11 @@ void emberAfFanControlClusterInitCallback(EndpointId endpoint)
199348
{
200349
VerifyOrDie(!mFanControlManager);
201350
mFanControlManager = std::make_unique<ChefFanControlManager>(endpoint);
202-
AttributeAccessInterfaceRegistry::Instance().Register(mFanControlManager.get());
203351
FanControl::SetDefaultDelegate(endpoint, mFanControlManager.get());
352+
mFanControlManager->Init();
353+
}
354+
355+
void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value)
356+
{
357+
mFanControlManager->HandleFanControlAttributeChange(attributeId, type, size, value);
204358
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <lib/core/DataModelTypes.h>
19+
20+
#ifdef MATTER_DM_PLUGIN_FAN_CONTROL_SERVER
21+
void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value);
22+
#endif

0 commit comments

Comments
 (0)