Skip to content

Commit 6ce6e25

Browse files
bhmanda-silabsrestyled-commitssabollim-silabs
authored
[SL-ONLY] Feature/rangehood app (#698)
* Added rangehood app * Cleanedup rangehoodapp * Resolved build errors * Added fanDelegate * Added button,LCD functionality to rangehood-app * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Removed speed related code * Removed duplicate file * Resolved review comments * seperating common code * restruncturing * PR comments * removing lightning feature in on/off * Restyled by whitespace * Restyled by clang-format * Removed step command and lighting attributes which are not required * Addressed review comments * Added return status code for get and set on/off state APIs * Resolved review comments * Resolved build errors * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Resolved review comments * Added construtor inplace of Init * Restyled by whitespace * Restyled by clang-format * Removed lock/unlock chipstack as it is having lock * Restyled by whitespace * Added a proper comment for lock/unlock chip stack * Restyled by clang-format * Added proper function comments * Restyled by whitespace * Restyled by clang-format * Removed updateFanMode for auto and smart fan modes * Resolved review comments * Restyled by whitespace * Resolved review comments * Resolved review comments * Restyled by clang-format * Added verifyReturnError instead of checking error in if else * Restyled by clang-format * Resolved review comments * Restyled by clang-format * Added error check in ToggleFanMode function * Resolved build error * Restyled by clang-format * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Update examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com> * Removed reacquiring lock to get actual value initialPercentSetting * Added status namespace * Restyled by clang-format * Added check for smart also when updating percentcurrent * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io> Co-authored-by: Satya Naag Bollimpalli <sabollim@silabs.com> Co-authored-by: sabollim-silabs <158290810+sabollim-silabs@users.noreply.github.com>
1 parent 67751c9 commit 6ce6e25

21 files changed

+7899
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
* Copyright (c) 2025 Google LLC.
5+
* All rights reserved.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <stdbool.h>
23+
#include <stdint.h>
24+
25+
#include <app/clusters/fan-control-server/fan-control-server.h>
26+
#include <app/data-model/Nullable.h>
27+
#include <lib/core/CHIPError.h>
28+
#include <lib/core/DataModelTypes.h>
29+
30+
class ExtractorHoodEndpoint
31+
{
32+
public:
33+
/**
34+
* @brief Construct the ExtractorHood endpoint.
35+
* @param endpointId The endpoint ID
36+
* @param lowPercent Percent value for Low mode (default: 30)
37+
* @param mediumPercent Percent value for Medium mode (default: 60)
38+
* @param highPercent Percent value for High/On mode (default: 100)
39+
*
40+
* Off is always 0 per spec: "The value 0 SHALL map to Off and be its own range".
41+
*/
42+
ExtractorHoodEndpoint(chip::EndpointId endpointId, chip::Percent lowPercent = 30, chip::Percent mediumPercent = 60,
43+
chip::Percent highPercent = 100) :
44+
mEndpointId(endpointId),
45+
mFanModeOffPercent(0), mFanModeLowPercent(lowPercent), mFanModeMediumPercent(mediumPercent),
46+
mFanModeHighPercent(highPercent)
47+
{}
48+
49+
/**
50+
* @brief Initialize the ExtractorHood endpoint runtime state.
51+
* Reads current PercentSetting and synchronizes PercentCurrent.
52+
*
53+
* @note Must be called after construction and after the Matter stack is initialized.
54+
* @return CHIP_NO_ERROR on success, error code otherwise
55+
*/
56+
CHIP_ERROR Init();
57+
58+
chip::app::DataModel::Nullable<chip::Percent> GetPercentSetting() const;
59+
60+
/**
61+
* @brief Get the FanMode attribute.
62+
**/
63+
64+
/**
65+
* @brief Get the FanMode attribute.
66+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
67+
*/
68+
CHIP_ERROR GetFanMode(chip::app::Clusters::FanControl::FanModeEnum & fanMode) const;
69+
70+
/** @brief Set the PercentCurrent attribute if it differs from the current value.
71+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
72+
*/
73+
CHIP_ERROR SetPercentCurrent(chip::Percent newPercentSetting);
74+
75+
/**
76+
* @brief Handle percent setting change and update percent current accordingly
77+
* @param newPercentSetting The new percent setting value
78+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
79+
*/
80+
CHIP_ERROR HandlePercentSettingChange(chip::Percent newPercentSetting);
81+
82+
/**
83+
* @brief Handle fan mode change and update percent current accordingly
84+
* @param newFanMode The new fan mode to apply
85+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
86+
*/
87+
CHIP_ERROR HandleFanModeChange(chip::app::Clusters::FanControl::FanModeEnum newFanMode);
88+
89+
/**
90+
* @brief Update the FanMode attribute
91+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
92+
*/
93+
CHIP_ERROR UpdateFanModeAttribute(chip::app::Clusters::FanControl::FanModeEnum newFanMode);
94+
95+
/**
96+
* @brief Toggle fan mode between Off and High
97+
* @return CHIP_ERROR on failure, CHIP_NO_ERROR on success
98+
*/
99+
CHIP_ERROR ToggleFanMode();
100+
101+
private:
102+
chip::EndpointId mEndpointId = chip::kInvalidEndpointId;
103+
104+
// Fan Mode Percent Mappings (set during initialization)
105+
chip::Percent mFanModeOffPercent;
106+
chip::Percent mFanModeLowPercent;
107+
chip::Percent mFanModeMediumPercent;
108+
chip::Percent mFanModeHighPercent;
109+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <app/clusters/on-off-server/on-off-server.h>
22+
#include <lib/core/CHIPError.h>
23+
#include <lib/core/DataModelTypes.h>
24+
25+
class LightEndpoint
26+
{
27+
public:
28+
LightEndpoint(chip::EndpointId endpointId) : mEndpointId(endpointId) {}
29+
30+
/**
31+
* @brief Get the current On/Off state from the Matter attribute.
32+
* The caller MUST hold the CHIP stack lock before calling this function,
33+
* unless calling from a CHIP task context where the lock is already held.
34+
* @param[out] state true if light is on, false if off on success.
35+
* @return Interaction Model status code.
36+
*/
37+
CHIP_ERROR GetOnOffState(bool & state);
38+
39+
/**
40+
* @brief Set On/Off state for the Light.
41+
* The caller MUST hold the CHIP stack lock before calling this function,
42+
* unless calling from a CHIP task context where the lock is already held.
43+
* @param[in] state Desired state (true => On, false => Off).
44+
* @return Interaction Model status code.
45+
*/
46+
CHIP_ERROR SetOnOffState(bool state);
47+
48+
private:
49+
chip::EndpointId mEndpointId = chip::kInvalidEndpointId;
50+
};
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "ExtractorHoodEndpoint.h"
20+
21+
#include <app-common/zap-generated/attributes/Accessors.h>
22+
#include <app/clusters/fan-control-server/fan-control-server.h>
23+
#include <lib/core/CHIPError.h>
24+
#include <lib/support/logging/CHIPLogging.h>
25+
#include <platform/CHIPDeviceLayer.h>
26+
27+
#include <algorithm>
28+
29+
using namespace chip;
30+
using namespace chip::app;
31+
using namespace chip::DeviceLayer;
32+
using namespace chip::app::Clusters;
33+
using namespace chip::app::Clusters::FanControl;
34+
using Status = chip::Protocols::InteractionModel::Status;
35+
36+
CHIP_ERROR ExtractorHoodEndpoint::Init()
37+
{
38+
// Initialize percent current from percent setting
39+
// This ensures the fan speed reflects the current setting on startup
40+
DeviceLayer::PlatformMgr().LockChipStack();
41+
DataModel::Nullable<chip::Percent> percentSettingNullable = GetPercentSetting();
42+
Percent initialPercentSetting = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value();
43+
CHIP_ERROR err = HandlePercentSettingChange(initialPercentSetting);
44+
DeviceLayer::PlatformMgr().UnlockChipStack();
45+
if (err != CHIP_NO_ERROR)
46+
{
47+
ChipLogError(NotSpecified, "ExtractorHoodEndpoint::Init: Failed to initialize PercentCurrent");
48+
return err;
49+
}
50+
51+
return CHIP_NO_ERROR;
52+
}
53+
54+
/**
55+
* @brief Get the PercentSetting attribute.
56+
* The caller MUST hold the CHIP stack lock before calling this function,
57+
* unless calling from a CHIP task context where the lock is already held.
58+
*/
59+
DataModel::Nullable<Percent> ExtractorHoodEndpoint::GetPercentSetting() const
60+
{
61+
DataModel::Nullable<Percent> percentSetting;
62+
Status Status = Clusters::FanControl::Attributes::PercentSetting::Get(mEndpointId, percentSetting);
63+
VerifyOrReturnValue(Status == chip::Protocols::InteractionModel::Status::Success, DataModel::Nullable<Percent>(),
64+
ChipLogError(NotSpecified,
65+
"ExtractorHoodEndpoint::GetPercentSetting: failed to get PercentSetting attribute: %d",
66+
to_underlying(Status)));
67+
return percentSetting;
68+
}
69+
70+
/* The caller MUST hold the CHIP stack lock before calling this function,
71+
* unless calling from a CHIP task context where the lock is already held.
72+
*/
73+
74+
CHIP_ERROR ExtractorHoodEndpoint::GetFanMode(FanControl::FanModeEnum & fanMode) const
75+
{
76+
Status status = FanControl::Attributes::FanMode::Get(mEndpointId, &fanMode);
77+
VerifyOrReturnError(status == Status::Success, CHIP_ERROR_INTERNAL,
78+
ChipLogError(NotSpecified, "ExtractorHoodEndpoint::GetFanMode: failed to get FanMode attribute: %d",
79+
to_underlying(status)));
80+
return CHIP_NO_ERROR;
81+
}
82+
83+
/**
84+
* The caller MUST hold the CHIP stack lock before calling this function,
85+
* unless calling from a CHIP task context where the lock is already held.
86+
*/
87+
88+
CHIP_ERROR ExtractorHoodEndpoint::SetPercentCurrent(Percent newPercentSetting)
89+
{
90+
Percent currentPercentCurrent = 0;
91+
Status getStatus = FanControl::Attributes::PercentCurrent::Get(mEndpointId, &currentPercentCurrent);
92+
VerifyOrReturnError(getStatus == chip::Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL,
93+
ChipLogError(NotSpecified,
94+
"ExtractorHoodEndpoint::SetPercentCurrent: failed to get currentPercentCurrent: %d",
95+
to_underlying(getStatus)));
96+
// No update needed if value is unchanged
97+
VerifyOrReturnError(newPercentSetting != currentPercentCurrent, CHIP_NO_ERROR);
98+
Status setStatus = FanControl::Attributes::PercentCurrent::Set(mEndpointId, newPercentSetting);
99+
VerifyOrReturnError(setStatus == Status::Success, CHIP_ERROR_INTERNAL,
100+
ChipLogError(NotSpecified,
101+
"ExtractorHoodEndpoint::SetPercentCurrent: failed to update PercentCurrent attribute: %d",
102+
to_underlying(setStatus)));
103+
return CHIP_NO_ERROR;
104+
}
105+
106+
/**
107+
* @brief Handle a change to the PercentSetting attribute, updating PercentCurrent as needed.
108+
* The caller MUST hold the CHIP stack lock before calling this function,
109+
* unless calling from a CHIP task context where the lock is already held.
110+
*/
111+
112+
CHIP_ERROR ExtractorHoodEndpoint::HandlePercentSettingChange(Percent newPercentSetting)
113+
{
114+
ChipLogDetail(NotSpecified, "ExtractorHoodEndpoint::HandlePercentSettingChange: %d", newPercentSetting);
115+
Percent currentPercentCurrent = 0;
116+
Status getStatus = FanControl::Attributes::PercentCurrent::Get(mEndpointId, &currentPercentCurrent);
117+
VerifyOrReturnError(getStatus == Status::Success, CHIP_ERROR_INTERNAL,
118+
ChipLogError(NotSpecified,
119+
"ExtractorHoodEndpoint::HandlePercentSettingChange: failed to get PercentCurrent: %d",
120+
to_underlying(getStatus)));
121+
VerifyOrReturnError(newPercentSetting != currentPercentCurrent, CHIP_NO_ERROR);
122+
FanControl::FanModeEnum currentFanMode;
123+
Status fanModeStatus = FanControl::Attributes::FanMode::Get(mEndpointId, &currentFanMode);
124+
VerifyOrReturnError(fanModeStatus == Status::Success, CHIP_ERROR_INTERNAL,
125+
ChipLogError(NotSpecified, "ExtractorHoodEndpoint::HandlePercentSettingChange: failed to get FanMode: %d",
126+
to_underlying(fanModeStatus)));
127+
// Update PercentCurrent only fanmode other than auto or smart
128+
VerifyOrReturnError(currentFanMode != FanControl::FanModeEnum::kAuto && currentFanMode != FanControl::FanModeEnum::kSmart,
129+
CHIP_NO_ERROR);
130+
Status setStatus = FanControl::Attributes::PercentCurrent::Set(mEndpointId, newPercentSetting);
131+
VerifyOrReturnError(
132+
setStatus == Status::Success, CHIP_ERROR_INTERNAL,
133+
ChipLogError(NotSpecified,
134+
"ExtractorHoodEndpoint::HandlePercentSettingChange: failed to update PercentCurrent attribute: %d",
135+
to_underlying(setStatus)));
136+
return CHIP_NO_ERROR;
137+
}
138+
139+
CHIP_ERROR ExtractorHoodEndpoint::HandleFanModeChange(chip::app::Clusters::FanControl::FanModeEnum newFanMode)
140+
{
141+
ChipLogDetail(NotSpecified, "ExtractorHoodEndpoint::HandleFanModeChange: %d", (uint8_t) newFanMode);
142+
switch (newFanMode)
143+
{
144+
case FanControl::FanModeEnum::kOff:
145+
return SetPercentCurrent(mFanModeOffPercent);
146+
case FanControl::FanModeEnum::kLow:
147+
return SetPercentCurrent(mFanModeLowPercent);
148+
case FanControl::FanModeEnum::kMedium:
149+
return SetPercentCurrent(mFanModeMediumPercent);
150+
case FanControl::FanModeEnum::kOn:
151+
case FanControl::FanModeEnum::kHigh:
152+
return SetPercentCurrent(mFanModeHighPercent);
153+
case FanControl::FanModeEnum::kSmart:
154+
case FanControl::FanModeEnum::kAuto:
155+
ChipLogProgress(NotSpecified, "ExtractorHoodEndpoint::HandleFanModeChange: Auto");
156+
return CHIP_NO_ERROR;
157+
case FanControl::FanModeEnum::kUnknownEnumValue:
158+
ChipLogProgress(NotSpecified, "ExtractorHoodEndpoint::HandleFanModeChange: Unknown");
159+
return CHIP_NO_ERROR; // Don't treat unknown as error
160+
default:
161+
return CHIP_NO_ERROR;
162+
}
163+
}
164+
165+
/**
166+
* @brief Update the FanMode attribute.
167+
* The caller MUST hold the CHIP stack lock before calling this function,
168+
* unless calling from a CHIP task context where the lock is already held.
169+
*/
170+
171+
CHIP_ERROR ExtractorHoodEndpoint::UpdateFanModeAttribute(FanControl::FanModeEnum newFanMode)
172+
{
173+
Status setStatus = FanControl::Attributes::FanMode::Set(mEndpointId, newFanMode);
174+
VerifyOrReturnError(setStatus == Status::Success, CHIP_ERROR_INTERNAL,
175+
ChipLogError(NotSpecified,
176+
"ExtractorHoodEndpoint::UpdateFanModeAttribute: failed to update FanMode attribute: %d",
177+
to_underlying(setStatus)));
178+
return CHIP_NO_ERROR;
179+
}
180+
181+
/**
182+
* @brief Toggle fan mode between Off and High.
183+
* This is used for button press toggles.
184+
*/
185+
186+
CHIP_ERROR ExtractorHoodEndpoint::ToggleFanMode()
187+
{
188+
FanControl::FanModeEnum currentFanMode = FanControl::FanModeEnum::kUnknownEnumValue;
189+
CHIP_ERROR err = GetFanMode(currentFanMode);
190+
if (err != CHIP_NO_ERROR || currentFanMode == FanControl::FanModeEnum::kUnknownEnumValue)
191+
{
192+
ChipLogError(NotSpecified, "ExtractorHoodEndpoint::ToggleFanMode: failed to get current fan mode");
193+
return CHIP_ERROR_INTERNAL;
194+
}
195+
FanControl::FanModeEnum target =
196+
(currentFanMode == FanControl::FanModeEnum::kOff) ? FanControl::FanModeEnum::kHigh : FanControl::FanModeEnum::kOff;
197+
CHIP_ERROR Err = UpdateFanModeAttribute(target);
198+
VerifyOrReturnError(Err == CHIP_NO_ERROR, Err);
199+
// Ensure PercentCurrent is updated to match the new mode
200+
return HandleFanModeChange(target);
201+
}

0 commit comments

Comments
 (0)