Skip to content

Commit e103352

Browse files
Add chef sample app for dishwasher (#35465)
* Update Matter data model/ZAP config for dishwasher * Add support for dishwasher alarm cluster * Add support for dishwasher mode cluster * Add support for dishwasher mode cluster * Update operational state delegate Emberexteral write and read callback * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Update Zap config for dishwasher on TOT * Update Zap config for dishwasher on TOT * Resolve PR comments for dishwasher * Restyled by clang-format * rolve PR comments. --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 2ac9bed commit e103352

10 files changed

+1744
-97
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 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+
#include <app-common/zap-generated/cluster-objects.h>
19+
20+
using namespace chip;
21+
using namespace chip::app;
22+
using namespace chip::app::Clusters;
23+
24+
#ifdef MATTER_DM_PLUGIN_DISHWASHER_ALARM_SERVER
25+
#include <app/clusters/dishwasher-alarm-server/dishwasher-alarm-server.h>
26+
using namespace chip::app::Clusters::DishwasherAlarm;
27+
28+
class DishwasherAlarmDelegate : public Delegate
29+
{
30+
public:
31+
/**
32+
* @brief
33+
* A notification that the Mask attribute will be changed. When this happens, some previously suppressed
34+
* alarms may need to be enabled, and previously enabled alarms may need to be suppressed.
35+
* @param[in] mask The new value of the Mask attribute.
36+
* @return The cluster will do this update if ModifyEnabledAlarmsCallback() returns true.
37+
* The cluster will not do this update if ModifyEnabledAlarmsCallback() returns false.
38+
*/
39+
bool ModifyEnabledAlarmsCallback(const BitMask<AlarmMap> mask) override;
40+
41+
/**
42+
* @brief
43+
* A notification that resets active alarms (if possible)
44+
* @param[in] alarms The value of reset alarms
45+
* @return The cluster will reset active alarms if ResetAlarmsCallback() returns true.
46+
* The cluster will not reset active alarms if ResetAlarmsCallback() returns false.
47+
*/
48+
bool ResetAlarmsCallback(const BitMask<AlarmMap> alarms) override;
49+
50+
~DishwasherAlarmDelegate() = default;
51+
};
52+
53+
bool DishwasherAlarmDelegate::ModifyEnabledAlarmsCallback(const BitMask<AlarmMap> mask)
54+
{
55+
// placeholder implementation
56+
return true;
57+
}
58+
59+
bool DishwasherAlarmDelegate::ResetAlarmsCallback(const BitMask<AlarmMap> alarms)
60+
{
61+
// placeholder implementation
62+
return true;
63+
}
64+
65+
/*
66+
* An example to present device's endpointId
67+
*/
68+
static constexpr EndpointId kDemoEndpointId = 1;
69+
70+
void MatterDishwasherAlarmServerInit()
71+
{
72+
using namespace app::Clusters;
73+
using namespace app::Clusters::DishwasherAlarm;
74+
75+
static DishwasherAlarm::DishwasherAlarmDelegate delegate;
76+
DishwasherAlarm::SetDefaultDelegate(kDemoEndpointId, &delegate);
77+
78+
// Set Supported attribute = 0x3F = 63
79+
// Bit Name Value
80+
// 0 InflowError 1
81+
// 1 DrainError 1
82+
// 2 DoorError 1
83+
// 3 TempTooLow 1
84+
// 4 TempTooHigh 1
85+
// 5 WaterLevelError 1
86+
BitMask<AlarmMap> supported;
87+
supported.SetField(AlarmMap::kInflowError, 1);
88+
supported.SetField(AlarmMap::kDrainError, 1);
89+
supported.SetField(AlarmMap::kDoorError, 1);
90+
supported.SetField(AlarmMap::kTempTooLow, 1);
91+
supported.SetField(AlarmMap::kTempTooHigh, 1);
92+
supported.SetField(AlarmMap::kWaterLevelError, 1);
93+
DishwasherAlarmServer::Instance().SetSupportedValue(kDemoEndpointId, supported);
94+
95+
// Set Mask attribute = 0x0 = 0
96+
// Bit Name Value
97+
// 0 InflowError 0
98+
// 1 DrainError 0
99+
// 2 DoorError 0
100+
// 3 TempTooLow 0
101+
// 4 TempTooHigh 0
102+
// 5 WaterLevelError 0
103+
BitMask<AlarmMap> mask;
104+
mask.SetField(AlarmMap::kInflowError, 0);
105+
mask.SetField(AlarmMap::kDrainError, 0);
106+
mask.SetField(AlarmMap::kDoorError, 0);
107+
mask.SetField(AlarmMap::kTempTooLow, 0);
108+
mask.SetField(AlarmMap::kTempTooHigh, 0);
109+
mask.SetField(AlarmMap::kWaterLevelError, 0);
110+
DishwasherAlarmServer::Instance().SetMaskValue(kDemoEndpointId, mask);
111+
112+
// Set Latch attribute = 0x30
113+
// Bit Name Value
114+
// 0 InflowError 1
115+
// 1 DrainError 1
116+
// 2 DoorError 0
117+
// 3 TempTooLow 0
118+
// 4 TempTooHigh 0
119+
// 5 WaterLevelError 0
120+
BitMask<AlarmMap> latch;
121+
latch.SetField(AlarmMap::kInflowError, 1);
122+
latch.SetField(AlarmMap::kDrainError, 1);
123+
latch.SetField(AlarmMap::kDoorError, 0);
124+
latch.SetField(AlarmMap::kTempTooLow, 0);
125+
latch.SetField(AlarmMap::kTempTooHigh, 0);
126+
latch.SetField(AlarmMap::kWaterLevelError, 0);
127+
DishwasherAlarmServer::Instance().SetLatchValue(kDemoEndpointId, latch);
128+
129+
// Set State attribute = 0x00
130+
// Bit Name Value
131+
// 0 InflowError 0
132+
// 1 DrainError 0
133+
// 2 DoorError 0
134+
// 3 TempTooLow 0
135+
// 4 TempTooHigh 0
136+
// 5 WaterLevelError 0
137+
BitMask<AlarmMap> state;
138+
state.SetField(AlarmMap::kInflowError, 0);
139+
state.SetField(AlarmMap::kDrainError, 0);
140+
state.SetField(AlarmMap::kDoorError, 0);
141+
state.SetField(AlarmMap::kTempTooLow, 0);
142+
state.SetField(AlarmMap::kTempTooHigh, 0);
143+
state.SetField(AlarmMap::kWaterLevelError, 0);
144+
DishwasherAlarmServer::Instance().SetStateValue(kDemoEndpointId, state);
145+
}
146+
147+
#endif // MATTER_DM_PLUGIN_DISHWASHER_ALARM_SERVER
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 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+
#include <app-common/zap-generated/attributes/Accessors.h>
19+
#include <app/util/config.h>
20+
21+
using namespace chip;
22+
using namespace chip::app;
23+
using namespace chip::app::Clusters;
24+
using chip::Protocols::InteractionModel::Status;
25+
template <typename T>
26+
using List = chip::app::DataModel::List<T>;
27+
using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type;
28+
29+
#ifdef MATTER_DM_PLUGIN_DISHWASHER_MODE_SERVER
30+
#include <chef-dishwasher-mode-delegate-impl.h>
31+
using namespace chip::app::Clusters::DishwasherMode;
32+
33+
static std::unique_ptr<DishwasherModeDelegate> gDishwasherModeDelegate;
34+
static std::unique_ptr<ModeBase::Instance> gDishwasherModeInstance;
35+
36+
CHIP_ERROR DishwasherModeDelegate::Init()
37+
{
38+
return CHIP_NO_ERROR;
39+
}
40+
41+
void DishwasherModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response)
42+
{
43+
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
44+
}
45+
46+
CHIP_ERROR DishwasherModeDelegate::GetModeLabelByIndex(uint8_t modeIndex, chip::MutableCharSpan & label)
47+
{
48+
if (modeIndex >= ArraySize(kModeOptions))
49+
{
50+
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
51+
}
52+
return chip::CopyCharSpanToMutableCharSpan(kModeOptions[modeIndex].label, label);
53+
}
54+
55+
CHIP_ERROR DishwasherModeDelegate::GetModeValueByIndex(uint8_t modeIndex, uint8_t & value)
56+
{
57+
if (modeIndex >= ArraySize(kModeOptions))
58+
{
59+
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
60+
}
61+
value = kModeOptions[modeIndex].mode;
62+
return CHIP_NO_ERROR;
63+
}
64+
65+
CHIP_ERROR DishwasherModeDelegate::GetModeTagsByIndex(uint8_t modeIndex, List<ModeTagStructType> & tags)
66+
{
67+
if (modeIndex >= ArraySize(kModeOptions))
68+
{
69+
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
70+
}
71+
72+
if (tags.size() < kModeOptions[modeIndex].modeTags.size())
73+
{
74+
return CHIP_ERROR_INVALID_ARGUMENT;
75+
}
76+
77+
std::copy(kModeOptions[modeIndex].modeTags.begin(), kModeOptions[modeIndex].modeTags.end(), tags.begin());
78+
tags.reduce_size(kModeOptions[modeIndex].modeTags.size());
79+
80+
return CHIP_NO_ERROR;
81+
}
82+
83+
// ModeBase::Instance * DishwasherMode::Instance()
84+
// {
85+
// return gDishwasherModeInstance;
86+
// }
87+
88+
void DishwasherMode::Shutdown()
89+
{
90+
gDishwasherModeInstance.reset();
91+
gDishwasherModeDelegate.reset();
92+
}
93+
94+
chip::Protocols::InteractionModel::Status chefDishwasherModeWriteCallback(chip::EndpointId endpointId, chip::ClusterId clusterId,
95+
const EmberAfAttributeMetadata * attributeMetadata,
96+
uint8_t * buffer)
97+
{
98+
VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1
99+
VerifyOrDie(gDishwasherModeInstance != nullptr);
100+
chip::Protocols::InteractionModel::Status ret;
101+
chip::AttributeId attributeId = attributeMetadata->attributeId;
102+
103+
switch (attributeId)
104+
{
105+
case chip::app::Clusters::DishwasherMode::Attributes::CurrentMode::Id: {
106+
uint8_t m = static_cast<uint8_t>(buffer[0]);
107+
ret = gDishwasherModeInstance->UpdateCurrentMode(m);
108+
if (chip::Protocols::InteractionModel::Status::Success != ret)
109+
{
110+
ChipLogError(DeviceLayer, "Invalid Attribute Write to CurrentMode : %d", static_cast<int>(ret));
111+
}
112+
}
113+
break;
114+
default:
115+
ret = chip::Protocols::InteractionModel::Status::UnsupportedWrite;
116+
ChipLogError(DeviceLayer, "Unsupported Writng Attribute ID: %d", static_cast<int>(attributeId));
117+
break;
118+
}
119+
120+
return ret;
121+
}
122+
123+
chip::Protocols::InteractionModel::Status chefDishwasherModeReadCallback(chip::EndpointId endpointId, chip::ClusterId clusterId,
124+
const EmberAfAttributeMetadata * attributeMetadata,
125+
uint8_t * buffer, uint16_t maxReadLength)
126+
{
127+
VerifyOrReturnValue(maxReadLength == 1, chip::Protocols::InteractionModel::Status::ResourceExhausted);
128+
buffer[0] = gDishwasherModeInstance->GetCurrentMode();
129+
130+
chip::Protocols::InteractionModel::Status ret = chip::Protocols::InteractionModel::Status::Success;
131+
chip::AttributeId attributeId = attributeMetadata->attributeId;
132+
133+
switch (attributeId)
134+
{
135+
case chip::app::Clusters::DishwasherMode::Attributes::CurrentMode::Id: {
136+
*buffer = gDishwasherModeInstance->GetCurrentMode();
137+
ChipLogDetail(DeviceLayer, "Reading DishwasherMode CurrentMode : %d", static_cast<int>(attributeId));
138+
}
139+
break;
140+
default:
141+
ret = chip::Protocols::InteractionModel::Status::UnsupportedRead;
142+
ChipLogDetail(DeviceLayer, "Unsupported attributeId %d from reading DishwasherMode", static_cast<int>(attributeId));
143+
break;
144+
}
145+
146+
return ret;
147+
}
148+
149+
void emberAfDishwasherModeClusterInitCallback(chip::EndpointId endpointId)
150+
{
151+
VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1.
152+
VerifyOrDie(!gDishwasherModeDelegate && !gDishwasherModeInstance);
153+
154+
gDishwasherModeDelegate = std::make_unique<DishwasherModeDelegate>();
155+
gDishwasherModeInstance = std::make_unique<ModeBase::Instance>(gDishwasherModeDelegate.get(), endpointId, DishwasherMode::Id,
156+
chip::to_underlying(Feature::kOnOff));
157+
gDishwasherModeInstance->Init();
158+
}
159+
#endif // MATTER_DM_PLUGIN_DISHWASHER_MODE_SERVER
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 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/mode-base-server/mode-base-server.h>
22+
#include <app/util/config.h>
23+
#include <cstring>
24+
#include <utility>
25+
26+
using chip::Protocols::InteractionModel::Status;
27+
28+
namespace chip {
29+
namespace app {
30+
namespace Clusters {
31+
32+
namespace DishwasherMode {
33+
34+
const uint8_t ModeNormal = 0;
35+
const uint8_t ModeHeavy = 1;
36+
const uint8_t ModeLight = 2;
37+
38+
/// This is an application level delegate to handle DishwasherMode commands according to the specific business logic.
39+
class DishwasherModeDelegate : public ModeBase::Delegate
40+
{
41+
private:
42+
using ModeTagStructType = detail::Structs::ModeTagStruct::Type;
43+
ModeTagStructType modeTagsNormal[1] = { { .value = to_underlying(ModeTag::kNormal) } };
44+
ModeTagStructType modeTagsHeavy[2] = { { .value = to_underlying(ModeBase::ModeTag::kMax) },
45+
{ .value = to_underlying(ModeTag::kHeavy) } };
46+
ModeTagStructType modeTagsLight[3] = { { .value = to_underlying(ModeTag::kLight) },
47+
{ .value = to_underlying(ModeBase::ModeTag::kNight) },
48+
{ .value = to_underlying(ModeBase::ModeTag::kQuiet) } };
49+
50+
const detail::Structs::ModeOptionStruct::Type kModeOptions[3] = {
51+
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Normal"),
52+
.mode = ModeNormal,
53+
.modeTags = DataModel::List<const ModeTagStructType>(modeTagsNormal) },
54+
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Heavy"),
55+
.mode = ModeHeavy,
56+
.modeTags = DataModel::List<const ModeTagStructType>(modeTagsHeavy) },
57+
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Light"),
58+
.mode = ModeLight,
59+
.modeTags = DataModel::List<const ModeTagStructType>(modeTagsLight) }
60+
};
61+
62+
CHIP_ERROR Init() override;
63+
void HandleChangeToMode(uint8_t mode, ModeBase::Commands::ChangeToModeResponse::Type & response) override;
64+
65+
CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) override;
66+
CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override;
67+
CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List<ModeTagStructType> & tags) override;
68+
69+
public:
70+
~DishwasherModeDelegate() override = default;
71+
};
72+
73+
ModeBase::Instance * Instance();
74+
75+
void Shutdown();
76+
77+
} // namespace DishwasherMode
78+
79+
} // namespace Clusters
80+
} // namespace app
81+
} // namespace chip
82+
83+
#ifdef MATTER_DM_PLUGIN_DISHWASHER_MODE_SERVER
84+
chip::Protocols::InteractionModel::Status chefDishwasherModeWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId,
85+
const EmberAfAttributeMetadata * attributeMetadata,
86+
uint8_t * buffer);
87+
chip::Protocols::InteractionModel::Status chefDishwasherModeReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId,
88+
const EmberAfAttributeMetadata * attributeMetadata,
89+
uint8_t * buffer, uint16_t maxReadLength);
90+
#endif // MATTER_DM_PLUGIN_DISHWASHER_MODE_SERVER

0 commit comments

Comments
 (0)