|
24 | 24 | #include <app-common/zap-generated/cluster-objects.h>
|
25 | 25 | #include <app-common/zap-generated/ids/Attributes.h>
|
26 | 26 | #include <app-common/zap-generated/ids/Clusters.h>
|
| 27 | +#include <app/AttributeAccessInterfaceRegistry.h> |
27 | 28 | #include <app/CommandHandler.h>
|
28 | 29 | #include <app/ConcreteCommandPath.h>
|
29 | 30 | #include <app/clusters/fan-control-server/fan-control-server.h>
|
@@ -413,33 +414,75 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
|
413 | 414 | ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", to_underlying(status)));
|
414 | 415 | }
|
415 | 416 |
|
416 |
| - // Adjust PercentSetting from a speed value change for SpeedSetting |
417 |
| - // percent = floor( speed/SpeedMax * 100 ) |
418 |
| - uint8_t speedMax; |
419 |
| - status = SpeedMax::Get(attributePath.mEndpointId, &speedMax); |
420 |
| - VerifyOrReturn(Status::Success == status, |
421 |
| - ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", to_underlying(status))); |
| 417 | + // Adjust PercentSetting from a speed value change for SpeedSetting only when the SpeedSetting change was received |
| 418 | + // on a write command, not when it was changed by the server or the app logic. This avoids circular logic such as |
| 419 | + //(with a SpeedMax of 10): |
| 420 | + // 1. Client sets the PercetSetting to 25% |
| 421 | + // 2. Server sets the SpeedSetting to 3 through the server callbackm, which sets the PercentSetting to 30% |
| 422 | + // 3. Server sets the PercentSetting to 30% through the server callback |
| 423 | + } |
| 424 | + break; |
| 425 | + } |
| 426 | + default: |
| 427 | + break; |
| 428 | + } |
| 429 | +} |
422 | 430 |
|
423 |
| - DataModel::Nullable<Percent> currentPercentSetting; |
424 |
| - status = PercentSetting::Get(attributePath.mEndpointId, currentPercentSetting); |
425 |
| - VerifyOrReturn(Status::Success == status, |
426 |
| - ChipLogError(Zcl, "Failed to get PercentSetting with error: 0x%02x", to_underlying(status))); |
| 431 | +CHIP_ERROR FanControlAttributeAccessInterface::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) |
| 432 | +{ |
| 433 | + Status status = Status::Success; |
| 434 | + switch (aPath.mAttributeId) |
| 435 | + { |
| 436 | + case SpeedSetting::Id: { |
| 437 | + DataModel::Nullable<uint8_t> speedSetting; |
| 438 | + ReturnErrorOnFailure(aDecoder.Decode(speedSetting)); |
| 439 | + |
| 440 | + DataModel::Nullable<uint8_t> currentSpeedSetting; |
| 441 | + status = SpeedSetting::Get(aPath.mEndpointId, currentSpeedSetting); |
| 442 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
427 | 443 |
|
428 |
| - float speed = speedSetting.Value(); |
429 |
| - Percent percentSetting = static_cast<Percent>(speed / speedMax * 100); |
| 444 | + if (speedSetting != currentSpeedSetting) |
| 445 | + { |
| 446 | + status = SpeedSetting::Set(aPath.mEndpointId, speedSetting); |
| 447 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
| 448 | + // Skip the last step if we are writing NULL |
| 449 | + VerifyOrReturnValue(!speedSetting.IsNull(), CHIP_NO_ERROR); |
430 | 450 |
|
431 |
| - if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value()) |
| 451 | + if (SupportsMultiSpeed(aPath.mEndpointId)) |
432 | 452 | {
|
433 |
| - status = PercentSetting::Set(attributePath.mEndpointId, percentSetting); |
434 |
| - VerifyOrReturn(Status::Success == status, |
435 |
| - ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", to_underlying(status))); |
| 453 | + // If SpeedSetting is set to 0, the server SHALL set the FanMode attribute value to Off. |
| 454 | + if (speedSetting.Value() == 0) |
| 455 | + { |
| 456 | + status = SetFanModeToOff(aPath.mEndpointId); |
| 457 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
| 458 | + } |
| 459 | + |
| 460 | + // Adjust PercentSetting from a speed value change for SpeedSetting |
| 461 | + // percent = floor( speed/SpeedMax * 100 ) |
| 462 | + uint8_t speedMax; |
| 463 | + status = SpeedMax::Get(aPath.mEndpointId, &speedMax); |
| 464 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
| 465 | + |
| 466 | + DataModel::Nullable<Percent> currentPercentSetting; |
| 467 | + status = PercentSetting::Get(aPath.mEndpointId, currentPercentSetting); |
| 468 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
| 469 | + |
| 470 | + float speed = speedSetting.Value(); |
| 471 | + Percent percentSetting = static_cast<Percent>(speed / speedMax * 100); |
| 472 | + |
| 473 | + if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value()) |
| 474 | + { |
| 475 | + status = PercentSetting::Set(aPath.mEndpointId, percentSetting); |
| 476 | + ReturnLogErrorOnFailure(StatusIB(status).ToChipError()); |
| 477 | + } |
436 | 478 | }
|
437 | 479 | }
|
438 | 480 | break;
|
439 | 481 | }
|
440 | 482 | default:
|
441 | 483 | break;
|
442 | 484 | }
|
| 485 | + return CHIP_NO_ERROR; |
443 | 486 | }
|
444 | 487 |
|
445 | 488 | bool emberAfFanControlClusterStepCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath,
|
|
0 commit comments