From fa46be15006d0f3f09a3247c648fec74bc8280ff Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Mon, 27 Oct 2025 20:50:55 +0530 Subject: [PATCH 01/11] Added rangehood app --- .../rangehood-app-common/BUILD.gn | 26 + .../include/ExtractorHoodEndpoint.h | 76 + .../include/LightEndpoint.h | 58 + .../rangehood-app-common/rangehood-app.matter | 2449 ++++++++++ .../rangehood-app-common/rangehood-app.zap | 4034 +++++++++++++++++ .../src/ExtractorHoodEndpoint.cpp | 39 + .../src/LightEndpoint.cpp | 55 + examples/rangehood-app/silabs/.gn | 29 + examples/rangehood-app/silabs/BUILD.gn | 195 + .../silabs/build_for_wifi_args.gni | 22 + .../silabs/build_for_wifi_gnfile.gn | 29 + examples/rangehood-app/silabs/build_overrides | 1 + .../rangehood-app/silabs/include/AppConfig.h | 36 + .../rangehood-app/silabs/include/AppEvent.h | 40 + .../rangehood-app/silabs/include/AppTask.h | 102 + .../silabs/include/CHIPProjectConfig.h | 102 + .../silabs/include/RangeHoodManager.h | 179 + examples/rangehood-app/silabs/src/AppTask.cpp | 176 + .../silabs/src/DataModelCallbacks.cpp | 75 + .../silabs/src/RangeHoodManager.cpp | 561 +++ .../silabs/third_party/connectedhomeip | 1 + 21 files changed, 8285 insertions(+) create mode 100644 examples/rangehood-app/rangehood-app-common/BUILD.gn create mode 100644 examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h create mode 100644 examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h create mode 100644 examples/rangehood-app/rangehood-app-common/rangehood-app.matter create mode 100644 examples/rangehood-app/rangehood-app-common/rangehood-app.zap create mode 100644 examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp create mode 100644 examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp create mode 100644 examples/rangehood-app/silabs/.gn create mode 100644 examples/rangehood-app/silabs/BUILD.gn create mode 100644 examples/rangehood-app/silabs/build_for_wifi_args.gni create mode 100644 examples/rangehood-app/silabs/build_for_wifi_gnfile.gn create mode 120000 examples/rangehood-app/silabs/build_overrides create mode 100644 examples/rangehood-app/silabs/include/AppConfig.h create mode 100644 examples/rangehood-app/silabs/include/AppEvent.h create mode 100644 examples/rangehood-app/silabs/include/AppTask.h create mode 100644 examples/rangehood-app/silabs/include/CHIPProjectConfig.h create mode 100644 examples/rangehood-app/silabs/include/RangeHoodManager.h create mode 100644 examples/rangehood-app/silabs/src/AppTask.cpp create mode 100644 examples/rangehood-app/silabs/src/DataModelCallbacks.cpp create mode 100644 examples/rangehood-app/silabs/src/RangeHoodManager.cpp create mode 120000 examples/rangehood-app/silabs/third_party/connectedhomeip diff --git a/examples/rangehood-app/rangehood-app-common/BUILD.gn b/examples/rangehood-app/rangehood-app-common/BUILD.gn new file mode 100644 index 00000000000..91afe6040df --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") +import("${chip_root}/src/app/chip_data_model.gni") + +config("config") { + include_dirs = [ "common/include" ] +} + +chip_data_model("rangehood-app-common") { + zap_file = "rangehood-app.zap" + is_server = true +} diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h new file mode 100644 index 00000000000..86d59e559b6 --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -0,0 +1,76 @@ + GNU nano 6.2 ExtractorHoodEndpoint.h +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace ExtractorHood { + +class FanDelegate : public FanControl::Delegate +{ +public: + /** + * @brief + * This method handles the step command. This will happen as fast as possible. + * + * @param[in] aDirection the direction in which the speed should step + * @param[in] aWrap whether the speed should wrap or not + * @param[in] aLowestOff whether the device should consider the lowest setting as off + * + * @return Success On success. + * @return Other Value indicating it failed to execute the command. + */ + Protocols::InteractionModel::Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; + + FanDelegate(EndpointId aEndpoint) : mEndpoint(aEndpoint) {} + +protected: + EndpointId mEndpoint = 0; +} + +class ExtractorHoodEndpoint +{ +public: + ExtractorHoodEndpoint(EndpointId endpointId) : mEndpointId(endpointId) {} + + /** + * @brief Initialize the ExtractorHood endpoint. + */ + CHIP_ERROR Init(); + + /* Add ExtractorHoodEndpoint functions*/ + +private: + EndpointId mEndpointId = kInvalidEndpointId; +}; + +} // namespace ExtractorHood +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h new file mode 100644 index 00000000000..1ff4624c47a --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h @@ -0,0 +1,58 @@ +@@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace Light { + +class LightEndpoint +{ +public: + LightEndpoint(EndpointId endpointId) : mEndpointId(endpointId) {} + + /** + * @brief Initialize the Light endpoint. + */ + CHIP_ERROR Init(); + + /** + * @brief Handle the "on/off" command for the Light. + */ + bool GetOnOffState(); + + /** + * @brief Set On/Off state for the Light. + */ + void SetOnOffState(bool state); + +private: + bool currentOnOffState = false; + EndpointId mEndpointId = kInvalidEndpointId; +}; + +} // namespace Light +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/rangehood-app/rangehood-app-common/rangehood-app.matter b/examples/rangehood-app/rangehood-app-common/rangehood-app.matter new file mode 100644 index 00000000000..d6a791cf815 --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/rangehood-app.matter @@ -0,0 +1,2449 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +enum AreaTypeTag : enum8 { + kAisle = 0; + kAttic = 1; + kBackDoor = 2; + kBackYard = 3; + kBalcony = 4; + kBallroom = 5; + kBathroom = 6; + kBedroom = 7; + kBorder = 8; + kBoxroom = 9; + kBreakfastRoom = 10; + kCarport = 11; + kCellar = 12; + kCloakroom = 13; + kCloset = 14; + kConservatory = 15; + kCorridor = 16; + kCraftRoom = 17; + kCupboard = 18; + kDeck = 19; + kDen = 20; + kDining = 21; + kDrawingRoom = 22; + kDressingRoom = 23; + kDriveway = 24; + kElevator = 25; + kEnsuite = 26; + kEntrance = 27; + kEntryway = 28; + kFamilyRoom = 29; + kFoyer = 30; + kFrontDoor = 31; + kFrontYard = 32; + kGameRoom = 33; + kGarage = 34; + kGarageDoor = 35; + kGarden = 36; + kGardenDoor = 37; + kGuestBathroom = 38; + kGuestBedroom = 39; + kGuestRoom = 41; + kGym = 42; + kHallway = 43; + kHearthRoom = 44; + kKidsRoom = 45; + kKidsBedroom = 46; + kKitchen = 47; + kLaundryRoom = 49; + kLawn = 50; + kLibrary = 51; + kLivingRoom = 52; + kLounge = 53; + kMediaTVRoom = 54 [spec_name = "Media/TV Room"]; + kMudRoom = 55; + kMusicRoom = 56; + kNursery = 57; + kOffice = 58; + kOutdoorKitchen = 59; + kOutside = 60; + kPantry = 61; + kParkingLot = 62; + kParlor = 63; + kPatio = 64; + kPlayRoom = 65; + kPoolRoom = 66; + kPorch = 67; + kPrimaryBathroom = 68; + kPrimaryBedroom = 69; + kRamp = 70; + kReceptionRoom = 71; + kRecreationRoom = 72; + kRoof = 74; + kSauna = 75; + kScullery = 76; + kSewingRoom = 77; + kShed = 78; + kSideDoor = 79; + kSideYard = 80; + kSittingRoom = 81; + kSnug = 82; + kSpa = 83; + kStaircase = 84; + kSteamRoom = 85; + kStorageRoom = 86; + kStudio = 87; + kStudy = 88; + kSunRoom = 89; + kSwimmingPool = 90; + kTerrace = 91; + kUtilityRoom = 92; + kWard = 93; + kWorkshop = 94; + kToilet = 95; +} + +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + +enum LandmarkTag : enum8 { + kAirConditioner = 0; + kAirPurifier = 1; + kBackDoor = 2; + kBarStool = 3; + kBathMat = 4; + kBathtub = 5; + kBed = 6; + kBookshelf = 7; + kChair = 8; + kChristmasTree = 9; + kCoatRack = 10; + kCoffeeTable = 11; + kCookingRange = 12; + kCouch = 13; + kCountertop = 14; + kCradle = 15; + kCrib = 16; + kDesk = 17; + kDiningTable = 18; + kDishwasher = 19; + kDoor = 20; + kDresser = 21; + kLaundryDryer = 22; + kFan = 23; + kFireplace = 24; + kFreezer = 25; + kFrontDoor = 26; + kHighChair = 27; + kKitchenIsland = 28; + kLamp = 29; + kLitterBox = 30; + kMirror = 31; + kNightstand = 32; + kOven = 33; + kPetBed = 34; + kPetBowl = 35; + kPetCrate = 36; + kRefrigerator = 37; + kScratchingPost = 38; + kShoeRack = 39; + kShower = 40; + kSideDoor = 41; + kSink = 42; + kSofa = 43; + kStove = 44; + kTable = 45; + kToilet = 46; + kTrashCan = 47; + kLaundryWasher = 48; + kWindow = 49; + kWineCooler = 50; +} + +enum LocationTag : enum8 { + kIndoor = 0; + kOutdoor = 1; + kInside = 2; + kOutside = 3; +} + +enum MeasurementTypeEnum : enum16 { + kUnspecified = 0; + kVoltage = 1; + kActiveCurrent = 2; + kReactiveCurrent = 3; + kApparentCurrent = 4; + kActivePower = 5; + kReactivePower = 6; + kApparentPower = 7; + kRMSVoltage = 8; + kRMSCurrent = 9; + kRMSPower = 10; + kFrequency = 11; + kPowerFactor = 12; + kNeutralCurrent = 13; + kElectricalEnergy = 14; + kReactiveEnergy = 15; + kApparentEnergy = 16; + kSoilMoisture = 17; +} + +enum PositionTag : enum8 { + kLeft = 0; + kRight = 1; + kTop = 2; + kBottom = 3; + kMiddle = 4; + kRow = 5; + kColumn = 6; +} + +enum PowerThresholdSourceEnum : enum8 { + kContract = 0; + kRegulator = 1; + kEquipment = 2; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; +} + +enum StreamUsageEnum : enum8 { + kInternal = 0; + kRecording = 1; + kAnalysis = 2; + kLiveView = 3; +} + +enum TariffPriceTypeEnum : enum8 { + kStandard = 0; + kCritical = 1; + kVirtual = 2; + kIncentive = 3; + kIncentiveSignal = 4; +} + +enum TariffUnitEnum : enum8 { + kKWh = 0; + kKVAh = 1; +} + +enum TestGlobalEnum : enum8 { + kSomeValue = 0; + kSomeOtherValue = 1; + kFinalValue = 2; +} + +enum ThreeLevelAutoEnum : enum8 { + kAuto = 0; + kLow = 1; + kMedium = 2; + kHigh = 3; +} + +enum WebRTCEndReasonEnum : enum8 { + kICEFailed = 0; + kICETimeout = 1; + kUserHangup = 2; + kUserBusy = 3; + kReplaced = 4; + kNoUserMedia = 5; + kInviteTimeout = 6; + kAnsweredElsewhere = 7; + kOutOfResources = 8; + kMediaTimeout = 9; + kLowPower = 10; + kPrivacyMode = 11; + kUnknownReason = 12; +} + +bitmap TestGlobalBitmap : bitmap32 { + kFirstBit = 0x1; + kSecondBit = 0x2; +} + +struct CurrencyStruct { + int16u currency = 0; + int8u decimalPoints = 1; +} + +struct PriceStruct { + money amount = 0; + CurrencyStruct currency = 1; +} + +struct MeasurementAccuracyRangeStruct { + int64s rangeMin = 0; + int64s rangeMax = 1; + optional percent100ths percentMax = 2; + optional percent100ths percentMin = 3; + optional percent100ths percentTypical = 4; + optional int64u fixedMax = 5; + optional int64u fixedMin = 6; + optional int64u fixedTypical = 7; +} + +struct MeasurementAccuracyStruct { + MeasurementTypeEnum measurementType = 0; + boolean measured = 1; + int64s minMeasuredValue = 2; + int64s maxMeasuredValue = 3; + MeasurementAccuracyRangeStruct accuracyRanges[] = 4; +} + +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + +struct ICECandidateStruct { + char_string candidate = 0; + nullable char_string SDPMid = 1; + nullable int16u SDPMLineIndex = 2; +} + +struct ICEServerStruct { + char_string URLs[] = 0; + optional long_char_string<508> username = 1; + optional long_char_string<512> credential = 2; + optional int16u caid = 3; +} + +struct LocationDescriptorStruct { + char_string<128> locationName = 0; + nullable int16s floorNumber = 1; + nullable AreaTypeTag areaType = 2; +} + +struct PowerThresholdStruct { + optional power_mw powerThreshold = 0; + optional power_mva apparentPowerThreshold = 1; + nullable PowerThresholdSourceEnum powerThresholdSource = 2; +} + +struct SemanticTagStruct { + nullable vendor_id mfgCode = 0; + enum8 namespaceID = 1; + enum8 tag = 2; + optional nullable char_string<64> label = 3; +} + +struct TestGlobalStruct { + char_string<128> name = 0; + nullable TestGlobalBitmap myBitmap = 1; + optional nullable TestGlobalEnum myEnum = 2; +} + +struct ViewportStruct { + int16u x1 = 0; + int16u y1 = 1; + int16u x2 = 2; + int16u y2 = 3; +} + +fabric_scoped struct WebRTCSessionStruct { + int16u id = 0; + node_id peerNodeID = 1; + endpoint_no peerEndpointID = 2; + StreamUsageEnum streamUsage = 3; + nullable int16u videoStreamID = 4; + nullable int16u audioStreamID = 5; + boolean metadataEnabled = 6; + fabric_idx fabricIndex = 254; +} + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 6; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** This command starts or stops the receiving device identifying itself. */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** This command allows the support of feedback to the user, such as a certain light effect. */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** Attributes and commands for group configuration and manipulation. */ +cluster Groups = 4 { + revision 4; + + bitmap Feature : bitmap32 { + kGroupNames = 0x1; + } + + bitmap NameSupportBitmap : bitmap8 { + kGroupNames = 0x80; + } + + readonly attribute NameSupportBitmap nameSupport = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AddGroupRequest { + group_id groupID = 0; + char_string<16> groupName = 1; + } + + response struct AddGroupResponse = 0 { + enum8 status = 0; + group_id groupID = 1; + } + + request struct ViewGroupRequest { + group_id groupID = 0; + } + + response struct ViewGroupResponse = 1 { + enum8 status = 0; + group_id groupID = 1; + char_string<16> groupName = 2; + } + + request struct GetGroupMembershipRequest { + group_id groupList[] = 0; + } + + response struct GetGroupMembershipResponse = 2 { + nullable int8u capacity = 0; + group_id groupList[] = 1; + } + + request struct RemoveGroupRequest { + group_id groupID = 0; + } + + response struct RemoveGroupResponse = 3 { + enum8 status = 0; + group_id groupID = 1; + } + + request struct AddGroupIfIdentifyingRequest { + group_id groupID = 0; + char_string<16> groupName = 1; + } + + /** The AddGroup command allows a client to add group membership in a particular group for the server endpoint. */ + fabric command access(invoke: manage) AddGroup(AddGroupRequest): AddGroupResponse = 0; + /** The ViewGroup command allows a client to request that the server responds with a ViewGroupResponse command containing the name string for a particular group. */ + fabric command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1; + /** The GetGroupMembership command allows a client to inquire about the group membership of the server endpoint, in a number of ways. */ + fabric command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2; + /** The RemoveGroup command allows a client to request that the server removes the membership for the server endpoint, if any, in a particular group. */ + fabric command access(invoke: manage) RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3; + /** The RemoveAllGroups command allows a client to direct the server to remove all group associations for the server endpoint. */ + fabric command access(invoke: manage) RemoveAllGroups(): DefaultSuccess = 4; + /** The AddGroupIfIdentifying command allows a client to add group membership in a particular group for the server endpoint, on condition that the endpoint is identifying itself. */ + fabric command access(invoke: manage) AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5; +} + +/** Attributes and commands for switching devices between 'On' and 'Off' states. */ +cluster OnOff = 6 { + revision 6; + + enum DelayedAllOffEffectVariantEnum : enum8 { + kDelayedOffFastFade = 0; + kNoFade = 1; + kDelayedOffSlowFade = 2; + } + + enum DyingLightEffectVariantEnum : enum8 { + kDyingLightFadeOff = 0; + } + + enum EffectIdentifierEnum : enum8 { + kDelayedAllOff = 0; + kDyingLight = 1; + } + + enum StartUpOnOffEnum : enum8 { + kOff = 0; + kOn = 1; + kToggle = 2; + } + + bitmap Feature : bitmap32 { + kLighting = 0x1; + kDeadFrontBehavior = 0x2; + kOffOnly = 0x4; + } + + bitmap OnOffControlBitmap : bitmap8 { + kAcceptOnlyWhenOn = 0x1; + } + + readonly attribute boolean onOff = 0; + readonly attribute optional boolean globalSceneControl = 16384; + attribute optional int16u onTime = 16385; + attribute optional int16u offWaitTime = 16386; + attribute access(write: manage) optional nullable StartUpOnOffEnum startUpOnOff = 16387; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OffWithEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + enum8 effectVariant = 1; + } + + request struct OnWithTimedOffRequest { + OnOffControlBitmap onOffControl = 0; + int16u onTime = 1; + int16u offWaitTime = 2; + } + + /** On receipt of this command, a device SHALL enter its ‘Off’ state. This state is device dependent, but it is recommended that it is used for power off or similar functions. On receipt of the Off command, the OnTime attribute SHALL be set to 0. */ + command Off(): DefaultSuccess = 0; + /** On receipt of this command, a device SHALL enter its ‘On’ state. This state is device dependent, but it is recommended that it is used for power on or similar functions. On receipt of the On command, if the value of the OnTime attribute is equal to 0, the device SHALL set the OffWaitTime attribute to 0. */ + command On(): DefaultSuccess = 1; + /** On receipt of this command, if a device is in its ‘Off’ state it SHALL enter its ‘On’ state. Otherwise, if it is in its ‘On’ state it SHALL enter its ‘Off’ state. On receipt of the Toggle command, if the value of the OnOff attribute is equal to FALSE and if the value of the OnTime attribute is equal to 0, the device SHALL set the OffWaitTime attribute to 0. If the value of the OnOff attribute is equal to TRUE, the OnTime attribute SHALL be set to 0. */ + command Toggle(): DefaultSuccess = 2; + /** The OffWithEffect command allows devices to be turned off using enhanced ways of fading. */ + command OffWithEffect(OffWithEffectRequest): DefaultSuccess = 64; + /** This command allows the recall of the settings when the device was turned off. */ + command OnWithRecallGlobalScene(): DefaultSuccess = 65; + /** This command allows devices to be turned on for a specific duration with a guarded off duration so that SHOULD the device be subsequently turned off, further OnWithTimedOff commands, received during this time, are prevented from turning the devices back on. */ + command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +cluster Descriptor = 29 { + revision 3; + + bitmap Feature : bitmap32 { + kTagList = 0x1; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + readonly attribute DeviceTypeStruct deviceTypeList[] = 0; + readonly attribute cluster_id serverList[] = 1; + readonly attribute cluster_id clientList[] = 2; + readonly attribute endpoint_no partsList[] = 3; + readonly attribute optional SemanticTagStruct tagList[] = 4; + readonly attribute optional char_string<32> endpointUniqueID = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The Access Control Cluster exposes a data model view of a + Node's Access Control List (ACL), which codifies the rules used to manage + and enforce Access Control for the Node's endpoints and their associated + cluster instances. */ +cluster AccessControl = 31 { + revision 3; + + enum AccessControlAuxiliaryTypeEnum : enum8 { + kSystem = 0; + kGroupcast = 1; + } + + enum AccessControlEntryAuthModeEnum : enum8 { + kPASE = 1 [spec_name = "PASE"]; + kCASE = 2 [spec_name = "CASE"]; + kGroup = 3; + } + + enum AccessControlEntryPrivilegeEnum : enum8 { + kView = 1; + kProxyView = 2; + kOperate = 3; + kManage = 4; + kAdminister = 5; + } + + enum AccessRestrictionTypeEnum : enum8 { + kAttributeAccessForbidden = 0; + kAttributeWriteForbidden = 1; + kCommandForbidden = 2; + kEventForbidden = 3; + } + + enum ChangeTypeEnum : enum8 { + kChanged = 0; + kAdded = 1; + kRemoved = 2; + } + + bitmap Feature : bitmap32 { + kExtension = 0x1; + kManagedDevice = 0x2; + kAuxiliary = 0x4; + } + + struct AccessRestrictionStruct { + AccessRestrictionTypeEnum type = 0; + nullable int32u id = 1; + } + + struct CommissioningAccessRestrictionEntryStruct { + endpoint_no endpoint = 0; + cluster_id cluster = 1; + AccessRestrictionStruct restrictions[] = 2; + } + + fabric_scoped struct AccessRestrictionEntryStruct { + fabric_sensitive endpoint_no endpoint = 0; + fabric_sensitive cluster_id cluster = 1; + fabric_sensitive AccessRestrictionStruct restrictions[] = 2; + fabric_idx fabricIndex = 254; + } + + struct AccessControlTargetStruct { + nullable cluster_id cluster = 0; + nullable endpoint_no endpoint = 1; + nullable devtype_id deviceType = 2; + } + + fabric_scoped struct AccessControlEntryStruct { + fabric_sensitive AccessControlEntryPrivilegeEnum privilege = 1; + fabric_sensitive AccessControlEntryAuthModeEnum authMode = 2; + nullable fabric_sensitive int64u subjects[] = 3; + nullable fabric_sensitive AccessControlTargetStruct targets[] = 4; + optional fabric_sensitive AccessControlAuxiliaryTypeEnum auxiliaryType = 5; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct AccessControlExtensionStruct { + fabric_sensitive octet_string<128> data = 1; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlEntryChanged = 0 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlEntryStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlExtensionChanged = 1 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlExtensionStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) FabricRestrictionReviewUpdate = 2 { + int64u token = 0; + optional long_char_string instruction = 1; + optional long_char_string ARLRequestFlowUrl = 2; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AuxiliaryAccessUpdated = 3 { + nullable node_id adminNodeID = 0; + fabric_idx fabricIndex = 254; + } + + attribute access(read: administer, write: administer) AccessControlEntryStruct acl[] = 0; + attribute access(read: administer, write: administer) optional AccessControlExtensionStruct extension[] = 1; + readonly attribute int16u subjectsPerAccessControlEntry = 2; + readonly attribute int16u targetsPerAccessControlEntry = 3; + readonly attribute int16u accessControlEntriesPerFabric = 4; + readonly attribute optional CommissioningAccessRestrictionEntryStruct commissioningARL[] = 5; + readonly attribute optional AccessRestrictionEntryStruct arl[] = 6; + readonly attribute access(read: administer) optional AccessControlEntryStruct auxiliaryACL[] = 7; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ReviewFabricRestrictionsRequest { + CommissioningAccessRestrictionEntryStruct arl[] = 0; + } + + response struct ReviewFabricRestrictionsResponse = 1 { + int64u token = 0; + } + + /** This command signals to the service associated with the device vendor that the fabric administrator would like a review of the current restrictions on the accessing fabric. */ + fabric command access(invoke: administer) ReviewFabricRestrictions(ReviewFabricRestrictionsRequest): ReviewFabricRestrictionsResponse = 0; +} + +/** This cluster provides attributes and events for determining basic information about Nodes, which supports both + Commissioning and operational determination of Node characteristics, such as Vendor ID, Product ID and serial number, + which apply to the whole Node. Also allows setting user device information such as location. */ +cluster BasicInformation = 40 { + revision 5; + + enum ColorEnum : enum8 { + kBlack = 0; + kNavy = 1; + kGreen = 2; + kTeal = 3; + kMaroon = 4; + kPurple = 5; + kOlive = 6; + kGray = 7; + kBlue = 8; + kLime = 9; + kAqua = 10; + kRed = 11; + kFuchsia = 12; + kYellow = 13; + kWhite = 14; + kNickel = 15; + kChrome = 16; + kBrass = 17; + kCopper = 18; + kSilver = 19; + kGold = 20; + } + + enum ProductFinishEnum : enum8 { + kOther = 0; + kMatte = 1; + kSatin = 2; + kPolished = 3; + kRugged = 4; + kFabric = 5; + } + + struct CapabilityMinimaStruct { + int16u caseSessionsPerFabric = 0; + int16u subscriptionsPerFabric = 1; + } + + struct ProductAppearanceStruct { + ProductFinishEnum finish = 0; + nullable ColorEnum primaryColor = 1; + } + + critical event StartUp = 0 { + int32u softwareVersion = 0; + } + + critical event ShutDown = 1 { + } + + info event Leave = 2 { + fabric_idx fabricIndex = 0; + } + + info event ReachableChanged = 3 { + boolean reachableNewValue = 0; + } + + readonly attribute int16u dataModelRevision = 0; + readonly attribute char_string<32> vendorName = 1; + readonly attribute vendor_id vendorID = 2; + readonly attribute char_string<32> productName = 3; + readonly attribute int16u productID = 4; + attribute access(write: manage) char_string<32> nodeLabel = 5; + attribute access(write: administer) char_string<2> location = 6; + readonly attribute int16u hardwareVersion = 7; + readonly attribute char_string<64> hardwareVersionString = 8; + readonly attribute int32u softwareVersion = 9; + readonly attribute char_string<64> softwareVersionString = 10; + readonly attribute optional char_string<16> manufacturingDate = 11; + readonly attribute optional char_string<32> partNumber = 12; + readonly attribute optional long_char_string<256> productURL = 13; + readonly attribute optional char_string<64> productLabel = 14; + readonly attribute optional char_string<32> serialNumber = 15; + attribute access(write: manage) optional boolean localConfigDisabled = 16; + readonly attribute optional boolean reachable = 17; + readonly attribute char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + readonly attribute optional ProductAppearanceStruct productAppearance = 20; + readonly attribute int32u specificationVersion = 21; + readonly attribute int16u maxPathsPerInvoke = 22; + readonly attribute int32u configurationVersion = 24; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + command MfgSpecificPing(): DefaultSuccess = 0; +} + +/** Provides an interface for providing OTA software updates */ +cluster OtaSoftwareUpdateProvider = 41 { + revision 1; // NOTE: Default/not specifically set + + enum ApplyUpdateActionEnum : enum8 { + kProceed = 0; + kAwaitNextAction = 1; + kDiscontinue = 2; + } + + enum DownloadProtocolEnum : enum8 { + kBDXSynchronous = 0; + kBDXAsynchronous = 1; + kHTTPS = 2 [spec_name = "HTTPS"]; + kVendorSpecific = 3; + } + + enum StatusEnum : enum8 { + kUpdateAvailable = 0; + kBusy = 1; + kNotAvailable = 2; + kDownloadProtocolNotSupported = 3; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct QueryImageRequest { + vendor_id vendorID = 0; + int16u productID = 1; + int32u softwareVersion = 2; + DownloadProtocolEnum protocolsSupported[] = 3; + optional int16u hardwareVersion = 4; + optional char_string<2> location = 5; + optional boolean requestorCanConsent = 6; + optional octet_string<512> metadataForProvider = 7; + } + + response struct QueryImageResponse = 1 { + StatusEnum status = 0; + optional int32u delayedActionTime = 1; + optional char_string<256> imageURI = 2; + optional int32u softwareVersion = 3; + optional char_string<64> softwareVersionString = 4; + optional octet_string<32> updateToken = 5; + optional boolean userConsentNeeded = 6; + optional octet_string<512> metadataForRequestor = 7; + } + + request struct ApplyUpdateRequestRequest { + octet_string<32> updateToken = 0; + int32u newVersion = 1; + } + + response struct ApplyUpdateResponse = 3 { + ApplyUpdateActionEnum action = 0; + int32u delayedActionTime = 1; + } + + request struct NotifyUpdateAppliedRequest { + octet_string<32> updateToken = 0; + int32u softwareVersion = 1; + } + + /** Determine availability of a new Software Image */ + command QueryImage(QueryImageRequest): QueryImageResponse = 0; + /** Determine next action to take for a downloaded Software Image */ + command ApplyUpdateRequest(ApplyUpdateRequestRequest): ApplyUpdateResponse = 2; + /** Notify OTA Provider that an update was applied */ + command NotifyUpdateApplied(NotifyUpdateAppliedRequest): DefaultSuccess = 4; +} + +/** Provides an interface for downloading and applying OTA software updates */ +cluster OtaSoftwareUpdateRequestor = 42 { + revision 1; // NOTE: Default/not specifically set + + enum AnnouncementReasonEnum : enum8 { + kSimpleAnnouncement = 0; + kUpdateAvailable = 1; + kUrgentUpdateAvailable = 2; + } + + enum ChangeReasonEnum : enum8 { + kUnknown = 0; + kSuccess = 1; + kFailure = 2; + kTimeOut = 3; + kDelayByProvider = 4; + } + + enum UpdateStateEnum : enum8 { + kUnknown = 0; + kIdle = 1; + kQuerying = 2; + kDelayedOnQuery = 3; + kDownloading = 4; + kApplying = 5; + kDelayedOnApply = 6; + kRollingBack = 7; + kDelayedOnUserConsent = 8; + } + + fabric_scoped struct ProviderLocation { + node_id providerNodeID = 1; + endpoint_no endpoint = 2; + fabric_idx fabricIndex = 254; + } + + info event StateTransition = 0 { + UpdateStateEnum previousState = 0; + UpdateStateEnum newState = 1; + ChangeReasonEnum reason = 2; + nullable int32u targetSoftwareVersion = 3; + } + + critical event VersionApplied = 1 { + int32u softwareVersion = 0; + int16u productID = 1; + } + + info event DownloadError = 2 { + int32u softwareVersion = 0; + int64u bytesDownloaded = 1; + nullable int8u progressPercent = 2; + nullable int64s platformCode = 3; + } + + attribute access(write: administer) ProviderLocation defaultOTAProviders[] = 0; + readonly attribute boolean updatePossible = 1; + readonly attribute UpdateStateEnum updateState = 2; + readonly attribute nullable int8u updateStateProgress = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AnnounceOTAProviderRequest { + node_id providerNodeID = 0; + vendor_id vendorID = 1; + AnnouncementReasonEnum announcementReason = 2; + optional octet_string<512> metadataForNode = 3; + endpoint_no endpoint = 4; + } + + /** Announce the presence of an OTA Provider */ + command access(invoke: administer) AnnounceOTAProvider(AnnounceOTAProviderRequest): DefaultSuccess = 0; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing common languages, units of measurements, and numerical formatting + standards. As such, Nodes that visually or audibly convey information need a mechanism by which + they can be configured to use a user’s preferred language, units, etc */ +cluster LocalizationConfiguration = 43 { + revision 1; + + attribute access(write: manage) char_string<35> activeLocale = 0; + readonly attribute char_string supportedLocales[] = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing preferences for how dates and times are conveyed. As such, Nodes that visually + or audibly convey time information need a mechanism by which they can be configured to use a + user’s preferred format. */ +cluster TimeFormatLocalization = 44 { + revision 1; + + enum CalendarTypeEnum : enum8 { + kBuddhist = 0; + kChinese = 1; + kCoptic = 2; + kEthiopian = 3; + kGregorian = 4; + kHebrew = 5; + kIndian = 6; + kIslamic = 7; + kJapanese = 8; + kKorean = 9; + kPersian = 10; + kTaiwanese = 11; + kUseActiveLocale = 255; + } + + enum HourFormatEnum : enum8 { + k12hr = 0; + k24hr = 1; + kUseActiveLocale = 255; + } + + bitmap Feature : bitmap32 { + kCalendarFormat = 0x1; + } + + attribute access(write: manage) HourFormatEnum hourFormat = 0; + attribute access(write: manage) optional CalendarTypeEnum activeCalendarType = 1; + readonly attribute optional CalendarTypeEnum supportedCalendarTypes[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster is used to manage global aspects of the Commissioning flow. */ +cluster GeneralCommissioning = 48 { + revision 2; + + enum CommissioningErrorEnum : enum8 { + kOK = 0 [spec_name = "OK"]; + kValueOutsideRange = 1; + kInvalidAuthentication = 2; + kNoFailSafe = 3; + kBusyWithOtherAdmin = 4; + kRequiredTCNotAccepted = 5; + kTCAcknowledgementsNotReceived = 6; + kTCMinVersionNotMet = 7; + } + + enum NetworkRecoveryReasonEnum : enum8 { + kUnspecified = 0; + kAuth = 1; + kVisibility = 2; + } + + enum RegulatoryLocationTypeEnum : enum8 { + kIndoor = 0; + kOutdoor = 1; + kIndoorOutdoor = 2; + } + + bitmap Feature : bitmap32 { + kTermsAndConditions = 0x1; + kNetworkRecovery = 0x2; + } + + struct BasicCommissioningInfo { + int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; + } + + attribute access(write: administer) int64u breadcrumb = 0; + readonly attribute BasicCommissioningInfo basicCommissioningInfo = 1; + readonly attribute RegulatoryLocationTypeEnum regulatoryConfig = 2; + readonly attribute RegulatoryLocationTypeEnum locationCapability = 3; + readonly attribute boolean supportsConcurrentConnection = 4; + provisional readonly attribute access(read: administer) optional int16u TCAcceptedVersion = 5; + provisional readonly attribute access(read: administer) optional int16u TCMinRequiredVersion = 6; + provisional readonly attribute access(read: administer) optional bitmap16 TCAcknowledgements = 7; + provisional readonly attribute access(read: administer) optional boolean TCAcknowledgementsRequired = 8; + provisional readonly attribute access(read: administer) optional nullable int32u TCUpdateDeadline = 9; + provisional readonly attribute access(read: manage) optional octet_string<8> recoveryIdentifier = 10; + provisional readonly attribute access(read: manage) optional nullable NetworkRecoveryReasonEnum networkRecoveryReason = 11; + provisional readonly attribute optional boolean isCommissioningWithoutPower = 12; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ArmFailSafeRequest { + int16u expiryLengthSeconds = 0; + int64u breadcrumb = 1; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + char_string<128> debugText = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + char_string<2> countryCode = 1; + int64u breadcrumb = 2; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + request struct SetTCAcknowledgementsRequest { + int16u TCVersion = 0; + bitmap16 TCUserResponse = 1; + } + + response struct SetTCAcknowledgementsResponse = 7 { + CommissioningErrorEnum errorCode = 0; + } + + /** This command is used to arm or disarm the fail-safe timer. */ + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + /** This command is used to set the regulatory configuration for the device. */ + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + /** This command is used to indicate that the commissioning process is complete. */ + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; + /** This command is used to set the user acknowledgements received in the Enhanced Setup Flow Terms & Conditions into the node. */ + command access(invoke: administer) SetTCAcknowledgements(SetTCAcknowledgementsRequest): SetTCAcknowledgementsResponse = 6; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +cluster NetworkCommissioning = 49 { + revision 2; + + enum NetworkCommissioningStatusEnum : enum8 { + kSuccess = 0; + kOutOfRange = 1; + kBoundsExceeded = 2; + kNetworkIDNotFound = 3; + kDuplicateNetworkID = 4; + kNetworkNotFound = 5; + kRegulatoryError = 6; + kAuthFailure = 7; + kUnsupportedSecurity = 8; + kOtherConnectionFailure = 9; + kIPV6Failed = 10; + kIPBindFailed = 11; + kUnknownError = 12; + } + + enum WiFiBandEnum : enum8 { + k2G4 = 0 [spec_name = "2G4"]; + k3G65 = 1 [spec_name = "3G65"]; + k5G = 2 [spec_name = "5G"]; + k6G = 3 [spec_name = "6G"]; + k60G = 4 [spec_name = "60G"]; + k1G = 5 [spec_name = "1G"]; + } + + bitmap Feature : bitmap32 { + kWiFiNetworkInterface = 0x1; + kThreadNetworkInterface = 0x2; + kEthernetNetworkInterface = 0x4; + kPerDeviceCredentials = 0x8; + } + + bitmap ThreadCapabilitiesBitmap : bitmap16 { + kIsBorderRouterCapable = 0x1; + kIsRouterCapable = 0x2; + kIsSleepyEndDeviceCapable = 0x4; + kIsFullThreadDevice = 0x8; + kIsSynchronizedSleepyEndDeviceCapable = 0x10; + } + + bitmap WiFiSecurityBitmap : bitmap8 { + kUnencrypted = 0x1; + kWEP = 0x2 [spec_name = "WEP"]; + kWPAPersonal = 0x4 [spec_name = "WPA-PERSONAL"]; + kWPA2Personal = 0x8 [spec_name = "WPA2-PERSONAL"]; + kWPA3Personal = 0x10 [spec_name = "WPA3-PERSONAL"]; + kWPA3MatterPDC = 0x20 [spec_name = "WPA3-Matter-PDC"]; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + optional nullable octet_string<20> networkIdentifier = 2; + optional nullable octet_string<20> clientIdentifier = 3; + } + + struct ThreadInterfaceScanResultStruct { + int16u panId = 0; + int64u extendedPanId = 1; + char_string<16> networkName = 2; + int16u channel = 3; + int8u version = 4; + octet_string<8> extendedAddress = 5; + int8s rssi = 6; + int8u lqi = 7; + } + + struct WiFiInterfaceScanResultStruct { + WiFiSecurityBitmap security = 0; + octet_string<32> ssid = 1; + octet_string<6> bssid = 2; + int16u channel = 3; + WiFiBandEnum wiFiBand = 4; + int8s rssi = 5; + } + + readonly attribute access(read: administer) int8u maxNetworks = 0; + readonly attribute access(read: administer) NetworkInfoStruct networks[] = 1; + readonly attribute optional int8u scanMaxTimeSeconds = 2; + readonly attribute optional int8u connectMaxTimeSeconds = 3; + attribute access(write: administer) boolean interfaceEnabled = 4; + readonly attribute access(read: administer) nullable NetworkCommissioningStatusEnum lastNetworkingStatus = 5; + readonly attribute access(read: administer) nullable octet_string<32> lastNetworkID = 6; + readonly attribute access(read: administer) nullable int32s lastConnectErrorValue = 7; + provisional readonly attribute optional WiFiBandEnum supportedWiFiBands[] = 8; + provisional readonly attribute optional ThreadCapabilitiesBitmap supportedThreadFeatures = 9; + provisional readonly attribute optional int16u threadVersion = 10; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ScanNetworksRequest { + optional nullable octet_string<32> ssid = 0; + optional int64u breadcrumb = 1; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + request struct AddOrUpdateWiFiNetworkRequest { + octet_string<32> ssid = 0; + octet_string<64> credentials = 1; + optional int64u breadcrumb = 2; + optional octet_string<140> networkIdentity = 3; + optional octet_string<20> clientIdentifier = 4; + optional octet_string<32> possessionNonce = 5; + } + + request struct AddOrUpdateThreadNetworkRequest { + octet_string<254> operationalDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string<512> debugText = 1; + optional int8u networkIndex = 2; + optional octet_string<140> clientIdentity = 3; + optional octet_string<64> possessionSignature = 4; + } + + request struct ConnectNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + nullable int32s errorValue = 2; + } + + request struct ReorderNetworkRequest { + octet_string<32> networkID = 0; + int8u networkIndex = 1; + optional int64u breadcrumb = 2; + } + + request struct QueryIdentityRequest { + octet_string<20> keyIdentifier = 0; + optional octet_string<32> possessionNonce = 1; + } + + response struct QueryIdentityResponse = 10 { + octet_string<140> identity = 0; + optional octet_string<64> possessionSignature = 1; + } + + /** Detemine the set of networks the device sees as available. */ + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + /** Add or update the credentials for a given Wi-Fi network. */ + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + /** Add or update the credentials for a given Thread network. */ + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + /** Remove the definition of a given network (including its credentials). */ + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + /** Connect to the specified network, using previously-defined credentials. */ + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + /** Modify the order in which networks will be presented in the Networks attribute. */ + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; + /** Retrieve details about and optionally proof of possession of a network client identity. */ + command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; +} + +/** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster GeneralDiagnostics = 51 { + revision 2; + + enum BootReasonEnum : enum8 { + kUnspecified = 0; + kPowerOnReboot = 1; + kBrownOutReset = 2; + kSoftwareWatchdogReset = 3; + kHardwareWatchdogReset = 4; + kSoftwareUpdateCompleted = 5; + kSoftwareReset = 6; + } + + enum HardwareFaultEnum : enum8 { + kUnspecified = 0; + kRadio = 1; + kSensor = 2; + kResettableOverTemp = 3; + kNonResettableOverTemp = 4; + kPowerSource = 5; + kVisualDisplayFault = 6; + kAudioOutputFault = 7; + kUserInterfaceFault = 8; + kNonVolatileMemoryError = 9; + kTamperDetected = 10; + } + + enum InterfaceTypeEnum : enum8 { + kUnspecified = 0; + kWiFi = 1; + kEthernet = 2; + kCellular = 3; + kThread = 4; + } + + enum NetworkFaultEnum : enum8 { + kUnspecified = 0; + kHardwareFailure = 1; + kNetworkJammed = 2; + kConnectionFailed = 3; + } + + enum RadioFaultEnum : enum8 { + kUnspecified = 0; + kWiFiFault = 1; + kCellularFault = 2; + kThreadFault = 3; + kNFCFault = 4; + kBLEFault = 5; + kEthernetFault = 6; + } + + bitmap Feature : bitmap32 { + kDataModelTest = 0x1; + } + + struct NetworkInterface { + char_string<32> name = 0; + boolean isOperational = 1; + nullable boolean offPremiseServicesReachableIPv4 = 2; + nullable boolean offPremiseServicesReachableIPv6 = 3; + octet_string<8> hardwareAddress = 4; + octet_string IPv4Addresses[] = 5; + octet_string IPv6Addresses[] = 6; + InterfaceTypeEnum type = 7; + } + + critical event HardwareFaultChange = 0 { + HardwareFaultEnum current[] = 0; + HardwareFaultEnum previous[] = 1; + } + + critical event RadioFaultChange = 1 { + RadioFaultEnum current[] = 0; + RadioFaultEnum previous[] = 1; + } + + critical event NetworkFaultChange = 2 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + critical event BootReason = 3 { + BootReasonEnum bootReason = 0; + } + + readonly attribute NetworkInterface networkInterfaces[] = 0; + readonly attribute int16u rebootCount = 1; + readonly attribute optional int64u upTime = 2; + readonly attribute optional int32u totalOperationalHours = 3; + readonly attribute optional BootReasonEnum bootReason = 4; + readonly attribute optional HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute optional RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute optional NetworkFaultEnum activeNetworkFaults[] = 7; + readonly attribute boolean testEventTriggersEnabled = 8; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct TestEventTriggerRequest { + octet_string<16> enableKey = 0; + int64u eventTrigger = 1; + } + + response struct TimeSnapshotResponse = 2 { + systime_ms systemTimeMs = 0; + nullable posix_ms posixTimeMs = 1; + } + + request struct PayloadTestRequestRequest { + octet_string<16> enableKey = 0; + int8u value = 1; + int16u count = 2; + } + + response struct PayloadTestResponse = 4 { + octet_string payload = 0; + } + + /** Provide a means for certification tests to trigger some test-plan-specific events */ + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; + /** Take a snapshot of system time and epoch time. */ + command TimeSnapshot(): TimeSnapshotResponse = 1; + /** Request a variable length payload response. */ + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; +} + +/** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster SoftwareDiagnostics = 52 { + revision 1; + + bitmap Feature : bitmap32 { + kWatermarks = 0x1; + } + + struct ThreadMetricsStruct { + int64u id = 0; + optional char_string<8> name = 1; + optional int32u stackFreeCurrent = 2; + optional int32u stackFreeMinimum = 3; + optional int32u stackSize = 4; + } + + info event SoftwareFault = 0 { + int64u id = 0; + optional char_string name = 1; + optional long_octet_string faultRecording = 2; + } + + readonly attribute optional ThreadMetricsStruct threadMetrics[] = 0; + readonly attribute optional int64u currentHeapFree = 1; + readonly attribute optional int64u currentHeapUsed = 2; + readonly attribute optional int64u currentHeapHighWatermark = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + /** This command is used to reset the high watermarks for heap and stack memory. */ + command access(invoke: manage) ResetWatermarks(): DefaultSuccess = 0; +} + +/** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster WiFiNetworkDiagnostics = 54 { + revision 1; + + enum AssociationFailureCauseEnum : enum8 { + kUnknown = 0; + kAssociationFailed = 1; + kAuthenticationFailed = 2; + kSsidNotFound = 3; + } + + enum ConnectionStatusEnum : enum8 { + kConnected = 0; + kNotConnected = 1; + } + + enum SecurityTypeEnum : enum8 { + kUnspecified = 0; + kNone = 1; + kWEP = 2 [spec_name = "WEP"]; + kWPA = 3 [spec_name = "WPA"]; + kWPA2 = 4 [spec_name = "WPA2"]; + kWPA3 = 5 [spec_name = "WPA3"]; + } + + enum WiFiVersionEnum : enum8 { + kA = 0; + kB = 1; + kG = 2; + kN = 3; + kAc = 4; + kAx = 5; + kAh = 6; + } + + bitmap Feature : bitmap32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + } + + info event Disconnection = 0 { + int16u reasonCode = 0; + } + + info event AssociationFailure = 1 { + AssociationFailureCauseEnum associationFailureCause = 0; + int16u status = 1; + } + + info event ConnectionStatus = 2 { + ConnectionStatusEnum connectionStatus = 0; + } + + readonly attribute nullable octet_string<6> bssid = 0; + readonly attribute nullable SecurityTypeEnum securityType = 1; + readonly attribute nullable WiFiVersionEnum wiFiVersion = 2; + readonly attribute nullable int16u channelNumber = 3; + readonly attribute nullable int8s rssi = 4; + readonly attribute optional nullable int32u beaconLostCount = 5; + readonly attribute optional nullable int32u beaconRxCount = 6; + readonly attribute optional nullable int32u packetMulticastRxCount = 7; + readonly attribute optional nullable int32u packetMulticastTxCount = 8; + readonly attribute optional nullable int32u packetUnicastRxCount = 9; + readonly attribute optional nullable int32u packetUnicastTxCount = 10; + readonly attribute optional nullable int64u currentMaxRate = 11; + readonly attribute optional nullable int64u overrunCount = 12; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + /** This command is used to reset the count attributes. */ + command ResetCounts(): DefaultSuccess = 0; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +cluster AdministratorCommissioning = 60 { + revision 1; + + enum CommissioningWindowStatusEnum : enum8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : enum8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + bitmap Feature : bitmap32 { + kBasic = 0x1; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable vendor_id adminVendorId = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OpenCommissioningWindowRequest { + int16u commissioningTimeout = 0; + octet_string<97> PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + int16u commissioningTimeout = 0; + } + + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode. */ + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + /** This command MAY be used by a current Administrator to instruct a Node to go into commissioning mode, if the node supports the Basic Commissioning Method. */ + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + /** This command is used by a current Administrator to instruct a Node to revoke any active OpenCommissioningWindow or OpenBasicCommissioningWindow command. */ + timed command access(invoke: administer) RevokeCommissioning(): DefaultSuccess = 2; +} + +/** This cluster is used to add or remove Operational Credentials on a Commissionee or Node, as well as manage the associated Fabrics. */ +cluster OperationalCredentials = 62 { + revision 2; + + enum CertificateChainTypeEnum : enum8 { + kDACCertificate = 1; + kPAICertificate = 2; + } + + enum NodeOperationalCertStatusEnum : enum8 { + kOK = 0 [spec_name = "OK"]; + kInvalidPublicKey = 1; + kInvalidNodeOpId = 2; + kInvalidNOC = 3; + kMissingCsr = 4; + kTableFull = 5; + kInvalidAdminSubject = 6; + kFabricConflict = 9; + kLabelConflict = 10; + kInvalidFabricIndex = 11; + } + + fabric_scoped struct FabricDescriptorStruct { + octet_string<65> rootPublicKey = 1; + vendor_id vendorID = 2; + fabric_id fabricID = 3; + node_id nodeID = 4; + char_string<32> label = 5; + optional octet_string<85> VIDVerificationStatement = 6; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct NOCStruct { + octet_string<400> noc = 1; + nullable octet_string<400> icac = 2; + optional octet_string<400> vvsc = 3; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: administer) NOCStruct NOCs[] = 0; + readonly attribute FabricDescriptorStruct fabrics[] = 1; + readonly attribute int8u supportedFabrics = 2; + readonly attribute int8u commissionedFabrics = 3; + readonly attribute octet_string trustedRootCertificates[] = 4; + readonly attribute int8u currentFabricIndex = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AttestationRequestRequest { + octet_string<32> attestationNonce = 0; + } + + response struct AttestationResponse = 1 { + octet_string attestationElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + response struct CertificateChainResponse = 3 { + octet_string<600> certificate = 0; + } + + request struct CSRRequestRequest { + octet_string<32> CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + response struct CSRResponse = 5 { + octet_string NOCSRElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct AddNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + octet_string<16> IPKValue = 2; + int64u caseAdminSubject = 3; + vendor_id adminVendorId = 4; + } + + request struct UpdateNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional char_string<128> debugText = 2; + } + + request struct UpdateFabricLabelRequest { + char_string<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + octet_string<400> rootCACertificate = 0; + } + + request struct SetVIDVerificationStatementRequest { + optional vendor_id vendorID = 0; + optional octet_string<85> VIDVerificationStatement = 1; + optional octet_string<400> vvsc = 2; + } + + request struct SignVIDVerificationRequestRequest { + fabric_idx fabricIndex = 0; + octet_string<32> clientChallenge = 1; + } + + response struct SignVIDVerificationResponse = 14 { + fabric_idx fabricIndex = 0; + int8u fabricBindingVersion = 1; + octet_string signature = 2; + } + + /** Sender is requesting attestation information from the receiver. */ + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + /** Sender is requesting a device attestation certificate from the receiver. */ + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + /** Sender is requesting a certificate signing request (CSR) from the receiver. */ + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + /** Sender is requesting to add the new node operational certificates. */ + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + /** This command SHALL replace the NOC and optional associated ICAC (if present) scoped under the accessing fabric upon successful validation of all arguments and preconditions. */ + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + /** This command SHALL be used by an Administrative Node to set the user-visible Label field for a given Fabric, as reflected by entries in the Fabrics attribute. */ + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + /** This command is used by Administrative Nodes to remove a given fabric index and delete all associated fabric-scoped data. */ + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + /** This command SHALL add a Trusted Root CA Certificate, provided as its CHIP Certificate representation. */ + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; + /** This command SHALL be used to update any of the accessing fabric's associated VendorID, VidVerificatioNStatement or VVSC (Vendor Verification Signing Certificate). */ + fabric command access(invoke: administer) SetVIDVerificationStatement(SetVIDVerificationStatementRequest): DefaultSuccess = 12; + /** This command SHALL be used to request that the server authenticate the fabric associated with the FabricIndex given. */ + command access(invoke: administer) SignVIDVerificationRequest(SignVIDVerificationRequestRequest): SignVIDVerificationResponse = 13; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +cluster GroupKeyManagement = 63 { + revision 2; + + enum GroupKeySecurityPolicyEnum : enum8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + bitmap Feature : bitmap32 { + kCacheAndSync = 0x1; + } + + fabric_scoped struct GroupInfoMapStruct { + group_id groupId = 1; + endpoint_no endpoints[] = 2; + optional char_string<16> groupName = 3; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct GroupKeyMapStruct { + group_id groupId = 1; + int16u groupKeySetID = 2; + fabric_idx fabricIndex = 254; + } + + struct GroupKeySetStruct { + int16u groupKeySetID = 0; + GroupKeySecurityPolicyEnum groupKeySecurityPolicy = 1; + nullable octet_string<16> epochKey0 = 2; + nullable epoch_us epochStartTime0 = 3; + nullable octet_string<16> epochKey1 = 4; + nullable epoch_us epochStartTime1 = 5; + nullable octet_string<16> epochKey2 = 6; + nullable epoch_us epochStartTime2 = 7; + } + + attribute access(write: manage) GroupKeyMapStruct groupKeyMap[] = 0; + readonly attribute GroupInfoMapStruct groupTable[] = 1; + readonly attribute int16u maxGroupsPerFabric = 2; + readonly attribute int16u maxGroupKeysPerFabric = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct KeySetWriteRequest { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetReadRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetRemoveRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + int16u groupKeySetIDs[] = 0; + } + + /** Write a new set of keys for the given key set id. */ + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + /** Read the keys for a given key set id. */ + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + /** Revoke a Root Key from a Group */ + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + /** Return the list of Group Key Sets associated with the accessing fabric */ + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +/** The Fixed Label Cluster provides a feature for the device to tag an endpoint with zero or more read only +labels. */ +cluster FixedLabel = 64 { + revision 1; // NOTE: Default/not specifically set + + shared struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + readonly attribute LabelStruct labelList[] = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The User Label Cluster provides a feature to tag an endpoint with zero or more labels. */ +cluster UserLabel = 65 { + revision 1; // NOTE: Default/not specifically set + + shared struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + attribute access(write: manage) LabelStruct labelList[] = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Attributes and commands for scene configuration and manipulation. */ +provisional cluster ScenesManagement = 98 { + revision 1; + + bitmap CopyModeBitmap : bitmap8 { + kCopyAllScenes = 0x1; + } + + bitmap Feature : bitmap32 { + kSceneNames = 0x1; + } + + struct AttributeValuePairStruct { + attrib_id attributeID = 0; + optional int8u valueUnsigned8 = 1; + optional int8s valueSigned8 = 2; + optional int16u valueUnsigned16 = 3; + optional int16s valueSigned16 = 4; + optional int32u valueUnsigned32 = 5; + optional int32s valueSigned32 = 6; + optional int64u valueUnsigned64 = 7; + optional int64s valueSigned64 = 8; + } + + struct ExtensionFieldSetStruct { + cluster_id clusterID = 0; + AttributeValuePairStruct attributeValueList[] = 1; + } + + fabric_scoped struct SceneInfoStruct { + int8u sceneCount = 0; + fabric_sensitive int8u currentScene = 1; + fabric_sensitive group_id currentGroup = 2; + fabric_sensitive boolean sceneValid = 3; + int8u remainingCapacity = 4; + fabric_idx fabricIndex = 254; + } + + readonly attribute int16u sceneTableSize = 1; + readonly attribute SceneInfoStruct fabricSceneInfo[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AddSceneRequest { + group_id groupID = 0; + int8u sceneID = 1; + int32u transitionTime = 2; + char_string<16> sceneName = 3; + ExtensionFieldSetStruct extensionFieldSetStructs[] = 4; + } + + response struct AddSceneResponse = 0 { + status status = 0; + group_id groupID = 1; + int8u sceneID = 2; + } + + request struct ViewSceneRequest { + group_id groupID = 0; + int8u sceneID = 1; + } + + response struct ViewSceneResponse = 1 { + status status = 0; + group_id groupID = 1; + int8u sceneID = 2; + optional int32u transitionTime = 3; + optional char_string<16> sceneName = 4; + optional ExtensionFieldSetStruct extensionFieldSetStructs[] = 5; + } + + request struct RemoveSceneRequest { + group_id groupID = 0; + int8u sceneID = 1; + } + + response struct RemoveSceneResponse = 2 { + status status = 0; + group_id groupID = 1; + int8u sceneID = 2; + } + + request struct RemoveAllScenesRequest { + group_id groupID = 0; + } + + response struct RemoveAllScenesResponse = 3 { + status status = 0; + group_id groupID = 1; + } + + request struct StoreSceneRequest { + group_id groupID = 0; + int8u sceneID = 1; + } + + response struct StoreSceneResponse = 4 { + status status = 0; + group_id groupID = 1; + int8u sceneID = 2; + } + + request struct RecallSceneRequest { + group_id groupID = 0; + int8u sceneID = 1; + optional nullable int32u transitionTime = 2; + } + + request struct GetSceneMembershipRequest { + group_id groupID = 0; + } + + response struct GetSceneMembershipResponse = 6 { + status status = 0; + nullable int8u capacity = 1; + group_id groupID = 2; + optional int8u sceneList[] = 3; + } + + request struct CopySceneRequest { + CopyModeBitmap mode = 0; + group_id groupIdentifierFrom = 1; + int8u sceneIdentifierFrom = 2; + group_id groupIdentifierTo = 3; + int8u sceneIdentifierTo = 4; + } + + response struct CopySceneResponse = 64 { + status status = 0; + group_id groupIdentifierFrom = 1; + int8u sceneIdentifierFrom = 2; + } + + /** Add a scene to the scene table. Extension field sets are input as '{"ClusterID": VALUE, "AttributeValueList":[{"AttributeID": VALUE, "Value*": VALUE}]}'. */ + fabric command access(invoke: manage) AddScene(AddSceneRequest): AddSceneResponse = 0; + /** Retrieves the requested scene entry from its Scene table. */ + fabric command ViewScene(ViewSceneRequest): ViewSceneResponse = 1; + /** Removes the requested scene entry, corresponding to the value of the GroupID field, from its Scene Table */ + fabric command access(invoke: manage) RemoveScene(RemoveSceneRequest): RemoveSceneResponse = 2; + /** Remove all scenes, corresponding to the value of the GroupID field, from its Scene Table */ + fabric command access(invoke: manage) RemoveAllScenes(RemoveAllScenesRequest): RemoveAllScenesResponse = 3; + /** Adds the scene entry into its Scene Table along with all extension field sets corresponding to the current state of other clusters on the same endpoint */ + fabric command access(invoke: manage) StoreScene(StoreSceneRequest): StoreSceneResponse = 4; + /** Set the attributes and corresponding state for each other cluster implemented on the endpoint accordingly to the resquested scene entry in the Scene Table */ + fabric command RecallScene(RecallSceneRequest): DefaultSuccess = 5; + /** This command can be used to get the used scene identifiers within a certain group, for the endpoint that implements this cluster. */ + fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; + /** This command allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; +} + +/** An interface for controlling a fan in a heating/cooling system. */ +cluster FanControl = 514 { + revision 5; + + enum AirflowDirectionEnum : enum8 { + kForward = 0; + kReverse = 1; + } + + enum FanModeEnum : enum8 { + kOff = 0; + kLow = 1; + kMedium = 2; + kHigh = 3; + kOn = 4; + kAuto = 5; + kSmart = 6; + } + + enum FanModeSequenceEnum : enum8 { + kOffLowMedHigh = 0; + kOffLowHigh = 1; + kOffLowMedHighAuto = 2; + kOffLowHighAuto = 3; + kOffHighAuto = 4; + kOffHigh = 5; + } + + enum StepDirectionEnum : enum8 { + kIncrease = 0; + kDecrease = 1; + } + + bitmap Feature : bitmap32 { + kMultiSpeed = 0x1; + kAuto = 0x2; + kRocking = 0x4; + kWind = 0x8; + kStep = 0x10; + kAirflowDirection = 0x20; + } + + bitmap RockBitmap : bitmap8 { + kRockLeftRight = 0x1; + kRockUpDown = 0x2; + kRockRound = 0x4; + } + + bitmap WindBitmap : bitmap8 { + kSleepWind = 0x1; + kNaturalWind = 0x2; + } + + attribute FanModeEnum fanMode = 0; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; + attribute nullable percent percentSetting = 2; + readonly attribute percent percentCurrent = 3; + readonly attribute optional int8u speedMax = 4; + attribute optional nullable int8u speedSetting = 5; + readonly attribute optional int8u speedCurrent = 6; + readonly attribute optional RockBitmap rockSupport = 7; + attribute optional RockBitmap rockSetting = 8; + readonly attribute optional WindBitmap windSupport = 9; + attribute optional WindBitmap windSetting = 10; + attribute optional AirflowDirectionEnum airflowDirection = 11; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct StepRequest { + StepDirectionEnum direction = 0; + optional boolean wrap = 1; + optional boolean lowestOff = 2; + } + + /** This command speeds up or slows down the fan, in steps, without a client having to know the fan speed. */ + command Step(StepRequest): DefaultSuccess = 0; +} + +endpoint 0 { + device type ma_rootdevice = 22, version 1; + + binding cluster OtaSoftwareUpdateProvider; + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster AccessControl { + emits event AccessControlEntryChanged; + emits event AccessControlExtensionChanged; + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry; + callback attribute targetsPerAccessControlEntry; + callback attribute accessControlEntriesPerFabric; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster BasicInformation { + callback attribute dataModelRevision; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + callback attribute nodeLabel; + callback attribute location; + callback attribute hardwareVersion; + callback attribute hardwareVersionString; + callback attribute softwareVersion; + callback attribute softwareVersionString; + callback attribute manufacturingDate; + callback attribute partNumber; + callback attribute productURL; + callback attribute productLabel; + callback attribute serialNumber; + callback attribute localConfigDisabled; + callback attribute uniqueID; + callback attribute capabilityMinima; + callback attribute specificationVersion; + callback attribute maxPathsPerInvoke; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster OtaSoftwareUpdateRequestor { + callback attribute defaultOTAProviders; + ram attribute updatePossible default = 1; + ram attribute updateState default = 0; + ram attribute updateStateProgress default = 0; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AnnounceOTAProvider; + } + + server cluster LocalizationConfiguration { + persist attribute activeLocale default = "en-US"; + callback attribute supportedLocales; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster TimeFormatLocalization { + persist attribute hourFormat default = 0; + persist attribute activeCalendarType default = 0; + callback attribute supportedCalendarTypes; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster GeneralCommissioning { + callback attribute breadcrumb; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig; + callback attribute locationCapability; + callback attribute supportsConcurrentConnection; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command ArmFailSafe; + handle command ArmFailSafeResponse; + handle command SetRegulatoryConfig; + handle command SetRegulatoryConfigResponse; + handle command CommissioningComplete; + handle command CommissioningCompleteResponse; + } + + server cluster NetworkCommissioning { + callback attribute maxNetworks; + callback attribute networks; + callback attribute scanMaxTimeSeconds; + callback attribute connectMaxTimeSeconds; + callback attribute interfaceEnabled; + callback attribute lastNetworkingStatus; + callback attribute lastNetworkID; + callback attribute lastConnectErrorValue; + callback attribute supportedWiFiBands; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command ScanNetworks; + handle command ScanNetworksResponse; + handle command AddOrUpdateWiFiNetwork; + handle command AddOrUpdateThreadNetwork; + handle command RemoveNetwork; + handle command NetworkConfigResponse; + handle command ConnectNetwork; + handle command ConnectNetworkResponse; + handle command ReorderNetwork; + } + + server cluster GeneralDiagnostics { + emits event BootReason; + callback attribute networkInterfaces; + callback attribute rebootCount; + callback attribute upTime; + callback attribute totalOperationalHours; + callback attribute bootReason; + callback attribute activeHardwareFaults; + callback attribute activeRadioFaults; + callback attribute activeNetworkFaults; + callback attribute testEventTriggersEnabled default = false; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command TestEventTrigger; + handle command TimeSnapshot; + handle command TimeSnapshotResponse; + } + + server cluster SoftwareDiagnostics { + emits event SoftwareFault; + callback attribute threadMetrics; + callback attribute currentHeapFree; + callback attribute currentHeapUsed; + callback attribute currentHeapHighWatermark; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command ResetWatermarks; + } + + server cluster WiFiNetworkDiagnostics { + callback attribute bssid; + callback attribute securityType; + callback attribute wiFiVersion; + callback attribute channelNumber; + callback attribute rssi; + callback attribute beaconLostCount; + callback attribute beaconRxCount; + callback attribute packetMulticastRxCount; + callback attribute packetMulticastTxCount; + callback attribute packetUnicastRxCount; + callback attribute packetUnicastTxCount; + callback attribute currentMaxRate; + callback attribute overrunCount; + ram attribute featureMap default = 3; + ram attribute clusterRevision default = 1; + + handle command ResetCounts; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus; + callback attribute adminFabricIndex; + callback attribute adminVendorId; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + + handle command OpenCommissioningWindow; + handle command RevokeCommissioning; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command AttestationRequest; + handle command AttestationResponse; + handle command CertificateChainRequest; + handle command CertificateChainResponse; + handle command CSRRequest; + handle command CSRResponse; + handle command AddNOC; + handle command UpdateNOC; + handle command NOCResponse; + handle command UpdateFabricLabel; + handle command RemoveFabric; + handle command AddTrustedRootCertificate; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command KeySetWrite; + handle command KeySetRead; + handle command KeySetReadResponse; + handle command KeySetRemove; + handle command KeySetReadAllIndices; + handle command KeySetReadAllIndicesResponse; + } + + server cluster FixedLabel { + callback attribute labelList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster UserLabel { + callback attribute labelList; + callback attribute featureMap; + callback attribute clusterRevision; + } +} +endpoint 1 { + device type ma_extractor_hood = 122, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster FanControl { + ram attribute fanMode default = 0; + ram attribute fanModeSequence; + ram attribute percentSetting default = 0; + ram attribute percentCurrent; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 5; + } +} +endpoint 2 { + device type ma_onofflight = 256, version 1; + + + server cluster Identify { + callback attribute identifyTime; + callback attribute identifyType; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Groups { + ram attribute nameSupport default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command AddGroupResponse; + handle command AddGroup; + handle command ViewGroup; + handle command ViewGroupResponse; + handle command GetGroupMembershipResponse; + handle command GetGroupMembership; + handle command RemoveGroup; + handle command RemoveGroupResponse; + handle command RemoveAllGroups; + handle command AddGroupIfIdentifying; + } + + server cluster OnOff { + ram attribute onOff; + ram attribute globalSceneControl; + ram attribute onTime; + ram attribute offWaitTime; + ram attribute startUpOnOff; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 6; + + handle command Off; + handle command On; + handle command Toggle; + handle command OffWithEffect; + handle command OnWithRecallGlobalScene; + handle command OnWithTimedOff; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster ScenesManagement { + ram attribute sceneTableSize default = 16; + callback attribute fabricSceneInfo; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AddScene; + handle command AddSceneResponse; + handle command ViewSceneResponse; + handle command ViewScene; + handle command RemoveScene; + handle command RemoveSceneResponse; + handle command RemoveAllScenes; + handle command RemoveAllScenesResponse; + handle command StoreScene; + handle command StoreSceneResponse; + handle command RecallScene; + handle command GetSceneMembership; + handle command GetSceneMembershipResponse; + handle command CopySceneResponse; + handle command CopyScene; + } +} + + diff --git a/examples/rangehood-app/rangehood-app-common/rangehood-app.zap b/examples/rangehood-app/rangehood-app-common/rangehood-app.zap new file mode 100644 index 00000000000..488903c2837 --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/rangehood-app.zap @@ -0,0 +1,4034 @@ +{ + "fileFormat": 2, + "featureLevel": 107, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/zcl/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" + } + ], + "endpointTypes": [ + { + "id": 1, + "name": "MA-rootdevice", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "AccessControlEntryChanged", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AccessControlExtensionChanged", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ManufacturingDate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartNumber", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductURL", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "long_char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductLabel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SerialNumber", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LocalConfigDisabled", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UniqueID", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpecificationVersion", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPathsPerInvoke", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "OTA Software Update Provider", + "code": 41, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "QueryImageResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, + { + "name": "OTA Software Update Requestor", + "code": 42, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AnnounceOTAProvider", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "DefaultOTAProviders", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdatePossible", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpdateState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "UpdateStateEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpdateStateProgress", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ActiveLocale", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "en-US", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedLocales", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Time Format Localization", + "code": 44, + "mfgCode": null, + "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "HourFormat", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "HourFormatEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveCalendarType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "CalendarTypeEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedCalendarTypes", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ScanNetworks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ScanNetworksResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateWiFiNetwork", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateThreadNetwork", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NetworkConfigResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ConnectNetwork", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ConnectNetworkResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ReorderNetwork", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ScanMaxTimeSeconds", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ConnectMaxTimeSeconds", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedWiFiBands", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TotalOperationalHours", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BootReason", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "BootReasonEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveHardwareFaults", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveRadioFaults", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveNetworkFaults", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "false", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "BootReason", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Software Diagnostics", + "code": 52, + "mfgCode": null, + "define": "SOFTWARE_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ResetWatermarks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "ThreadMetrics", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentHeapFree", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentHeapUsed", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentHeapHighWatermark", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "SoftwareFault", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Wi-Fi Network Diagnostics", + "code": 54, + "mfgCode": null, + "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ResetCounts", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "BSSID", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SecurityType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SecurityTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WiFiVersion", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "WiFiVersionEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ChannelNumber", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RSSI", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int8s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BeaconLostCount", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BeaconRxCount", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketMulticastRxCount", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketMulticastTxCount", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketUnicastRxCount", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketUnicastTxCount", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMaxRate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OverrunCount", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Fixed Label", + "code": 64, + "mfgCode": null, + "define": "FIXED_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "User Label", + "code": 65, + "mfgCode": null, + "define": "USER_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 122, + "profileId": 259, + "label": "MA-extractor-hood", + "name": "MA-extractor-hood", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 122, + "profileId": 259, + "label": "MA-extractor-hood", + "name": "MA-extractor-hood", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 122 + ], + "deviceTypeName": "MA-extractor-hood", + "deviceTypeCode": 122, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Fan Control", + "code": 514, + "mfgCode": null, + "define": "FAN_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "FanMode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "FanModeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FanModeSequence", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "FanModeSequenceEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PercentSetting", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PercentCurrent", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 3, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 256, + "profileId": 259, + "label": "MA-onofflight", + "name": "MA-onofflight", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 256, + "profileId": 259, + "label": "MA-onofflight", + "name": "MA-onofflight", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 256 + ], + "deviceTypeName": "MA-onofflight", + "deviceTypeCode": 256, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AddGroupResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddGroup", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ViewGroup", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ViewGroupResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "GetGroupMembershipResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "GetGroupMembership", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveGroup", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveGroupResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveAllGroups", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddGroupIfIdentifying", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NameSupport", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "NameSupportBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OffWithEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OnWithRecallGlobalScene", + "code": 65, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OnWithTimedOff", + "code": 66, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GlobalSceneControl", + "code": 16384, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnTime", + "code": 16385, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OffWaitTime", + "code": 16386, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartUpOnOff", + "code": 16387, + "mfgCode": null, + "side": "server", + "type": "StartUpOnOffEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Scenes Management", + "code": 98, + "mfgCode": null, + "define": "SCENES_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "AddScene", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddSceneResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ViewSceneResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ViewScene", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveScene", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveSceneResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveAllScenes", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveAllScenesResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "StoreScene", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StoreSceneResponse", + "code": 4, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RecallScene", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetSceneMembership", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetSceneMembershipResponse", + "code": 6, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CopySceneResponse", + "code": 64, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CopyScene", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SceneTableSize", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "16", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FabricSceneInfo", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, + "networkId": 0, + "parentEndpointIdentifier": null + } + ] +} \ No newline at end of file diff --git a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp new file mode 100644 index 00000000000..59021be74bd --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RangeHoodManager.h" +#include "ExtractorHoodEndpoint.h" + +#include + + +using namespace chip; +using namespace chip::app::Clusters::ExtractorHood; + +CHIP_ERROR ExtractorHoodEndpoint::Init() +{ + return CHIP_NO_ERROR; +} + +Status FanDelegate::HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) +{ + ChipLogProgress(Zcl, "FanDelegate::HandleStep aDirection %d, aWrap %d, aLowestOff %d", to_underlying(aDirection), + aWrap, aLowestOff); + + RangeHoodManager::GetInstance().ProcessExtractorStepCommand(mEndpointId, aDirection, aWrap, aLowestOff); +} \ No newline at end of file diff --git a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp new file mode 100644 index 00000000000..98705d7631c --- /dev/null +++ b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp @@ -0,0 +1,55 @@ + +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LightEndpoint.h" + +#include +#include + +using namespace chip; +using namespace chip::app::Clusters::Light; + +CHIP_ERROR LightEndpoint::Init() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR LightEndpoint::Init() +{ + bool state = false; + OnOffServer::Instance().getOnOffValue(mEndpointId, &state); + return CHIP_NO_ERROR; +} + +bool LightEndpoint::GetOnOffState() +{ + bool state = false; + OnOffServer::Instance().getOnOffValue(mEndpointId, &state); + return state; +} + +void LightEndpoint::SetOnOffState(bool state) +{ + CommandId commandId = state ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id; + auto status = OnOffServer::Instance().setOnOffValue(mEndpointId, commandId, false); + if (status != Protocols::InteractionModel::Status::Success) + { + ChipLogError(AppServer, "ERR: updating on/off %x", to_underlying(status)); + } +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/.gn b/examples/rangehood-app/silabs/.gn new file mode 100644 index 00000000000..fe0e637d199 --- /dev/null +++ b/examples/rangehood-app/silabs/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + chip_openthread_ftd = true + + import("//openthread.gni") +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/BUILD.gn b/examples/rangehood-app/silabs/BUILD.gn new file mode 100644 index 00000000000..523f61263db --- /dev/null +++ b/examples/rangehood-app/silabs/BUILD.gn @@ -0,0 +1,195 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") + +import("${build_root}/config/defaults.gni") +import("${silabs_sdk_build_root}/silabs_executable.gni") + +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/silabs/silabs_board.gni") + +if (chip_enable_pw_rpc) { + import("//build_overrides/pigweed.gni") + import("$dir_pw_build/target_types.gni") +} + +assert(current_os == "freertos") + +silabs_project_dir = "${chip_root}/examples/rangehood-app/silabs" +examples_common_plat_dir = "${chip_root}/examples/platform/silabs" +example_rangehood_dir = "${chip_root}/examples/rangehood-app" + +if (wifi_soc) { + import("${chip_root}/third_party/silabs/SiWx917_sdk.gni") + examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917" +} + +import("${examples_common_plat_dir}/args.gni") + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +if (slc_generate) { + # Generate Project Specific config (Board, hardware used etc..) + print(exec_script("${chip_root}/third_party/silabs/slc_gen/run_slc.py", + [ + rebase_path(chip_root), + "${silabs_board}", + "${disable_lcd}", + "${use_wstk_buttons}", + "${use_wstk_leds}", + "${use_external_flash}", + "${silabs_mcu}", + rebase_path(slc_gen_path), + ], + "list lines")) +} + +if (wifi_soc) { + siwx917_sdk("sdk") { + sources = [ + "${examples_common_plat_dir}/FreeRTOSConfig.h", + "${silabs_project_dir}/include/CHIPProjectConfig.h", + ] + + include_dirs = [ + "${chip_root}/src/platform/silabs/SiWx917", + "${silabs_project_dir}/include", + "${examples_plat_dir}", + "${chip_root}/src/lib", + "${examples_common_plat_dir}", + ] + + defines = [] + if (chip_enable_pw_rpc) { + defines += [ + "HAL_VCOM_ENABLE=1", + "PW_RPC_ENABLED", + ] + } + } +} + +silabs_executable("rangehood_app") { + output_name = "matter-silabs-rangehood-example.out" + include_dirs = [ + "include", + "${example_rangehood_dir}/rangehood-app-common/include", + ] + defines = [] + + if (silabs_board == "BRD2704A") { + defines += [ "SL_STATUS_LED=0" ] + } + + sources = [ + "${example_rangehood_dir}/rangehood-app-common/src/ExtractorHoodEndpoint.cpp", + "${example_rangehood_dir}/rangehood-app-common/src/LightEndpoint.cpp", + "${examples_common_plat_dir}/main.cpp", + "src/AppTask.cpp", + "src/DataModelCallbacks.cpp", + "src/RangehoodManager.cpp", + ] + + deps = [ ":sdk" ] + + if (wifi_soc) { + deps += [ "${examples_plat_dir}:siwx917-common" ] + } + + if (chip_enable_pw_rpc) { + defines += [ + "PW_RPC_ENABLED", + "PW_RPC_ATTRIBUTE_SERVICE=1", + "PW_RPC_BUTTON_SERVICE=1", + "PW_RPC_DESCRIPTOR_SERVICE=1", + "PW_RPC_DEVICE_SERVICE=1", + "PW_RPC_LIGHTING_SERVICE=1", + "PW_RPC_OTCLI_SERVICE=1", + "PW_RPC_THREAD_SERVICE=1", + "PW_RPC_TRACING_SERVICE=1", + ] + + sources += [ + "${chip_root}/examples/common/pigweed/RpcService.cpp", + "${chip_root}/examples/common/pigweed/efr32/PigweedLoggerMutex.cpp", + "${examples_common_plat_dir}/PigweedLogger.cpp", + "${examples_common_plat_dir}/Rpc.cpp", + ] + + deps += [ + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_stream:sys_io_stream", + "$dir_pw_trace", + "$dir_pw_trace_tokenized", + "$dir_pw_trace_tokenized:trace_rpc_service", + "${chip_root}/config/efr32/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:attributes_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:button_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:descriptor_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:device_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:ot_cli_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:thread_service.nanopb_rpc", + ] + + if (wifi_soc) { + deps += [ "${examples_plat_dir}/pw_sys_io:pw_sys_io_siwx917" ] + } + + deps += pw_build_LINK_DEPS + + include_dirs += [ + "${chip_root}/examples/common", + "${chip_root}/examples/common/pigweed/efr32", + ] + } + + ldscript = "${examples_common_plat_dir}/ldscripts/${silabs_family}.ld" + + inputs = [ ldscript ] + + ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + # WiFi Settings + if (chip_enable_wifi) { + ldflags += [ + "-Wl,--defsym", + "-Wl,SILABS_WIFI=1", + ] + } + + output_dir = root_out_dir +} + +group("silabs") { + deps = [ ":oven_app" ] +} + +group("default") { + deps = [ ":silabs" ] +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/build_for_wifi_args.gni b/examples/rangehood-app/silabs/build_for_wifi_args.gni new file mode 100644 index 00000000000..300108d01cc --- /dev/null +++ b/examples/rangehood-app/silabs/build_for_wifi_args.gni @@ -0,0 +1,22 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build_overrides/chip.gni") + +silabs_sdk_target = get_label_info(":sdk", "label_no_toolchain") +chip_enable_openthread = false +import("${chip_root}/src/platform/silabs/wifi/args.gni") + +sl_enable_test_event_trigger = false +chip_enable_ota_requestor = false +app_data_model = "${chip_root}/examples/rangehood-app-common/rangehood-app-common" diff --git a/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn b/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn new file mode 100644 index 00000000000..b13f5432972 --- /dev/null +++ b/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + chip_enable_wifi = true + chip_device_platform = "SiWx917" + import("//build_for_wifi_args.gni") +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/build_overrides b/examples/rangehood-app/silabs/build_overrides new file mode 120000 index 00000000000..e578e73312e --- /dev/null +++ b/examples/rangehood-app/silabs/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/rangehood-app/silabs/include/AppConfig.h b/examples/rangehood-app/silabs/include/AppConfig.h new file mode 100644 index 00000000000..422336f7be0 --- /dev/null +++ b/examples/rangehood-app/silabs/include/AppConfig.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * Copyright (c) 2025 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "silabs_utils.h" + +// ---- RangeHood Example App Config ---- + +#define APP_TASK_NAME "RangeHood" + +#define BLE_DEV_NAME "SiLabs-RangeHood" + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOD_MS 10 + +// Endpoint definitions for rangehood app +#define FAN_ENDPOINT 1 +#define LIGHT_ENDPOINT 2 \ No newline at end of file diff --git a/examples/rangehood-app/silabs/include/AppEvent.h b/examples/rangehood-app/silabs/include/AppEvent.h new file mode 100644 index 00000000000..f5fb64ccfc9 --- /dev/null +++ b/examples/rangehood-app/silabs/include/AppEvent.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * Copyright (c) 2025 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BaseAppEvent.h" + +struct AppEvent : public BaseAppEvent +{ + enum AppEventTypes + { + kEventType_RangeHood = BaseAppEvent::kEventType_Max + 1, + kEventType_Install, + }; + + union + { + struct + { + uint8_t Action; + int32_t Actor; + } RangeHoodEvent; + }; +}; diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h new file mode 100644 index 00000000000..c7aa1493ad0 --- /dev/null +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * Copyright (c) 2025 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/********************************************************** + * Includes + *********************************************************/ + +#include +#include + +#include "AppEvent.h" +#include "BaseApplication.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include +#include + +/********************************************************** + * Defines + *********************************************************/ + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +/********************************************************** + * AppTask Declaration + *********************************************************/ + +class AppTask : public BaseApplication +{ + +public: + AppTask() = default; + + static AppTask & GetAppTask() { return sAppTask; } + + /** + * @brief AppTask task main loop function + * + * @param pvParameter FreeRTOS task parameter + */ + static void AppTaskMain(void * pvParameter); + + CHIP_ERROR StartAppTask(); + + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param buttonHandle APP_FUNCTION_BUTTON + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED + */ + static void ButtonEventHandler(uint8_t button, uint8_t btnAction); + +private: + static AppTask sAppTask; + + static void ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * value); + static void ActionCompleted(RangeHoodManager::Action_t aAction); + + /** + * @brief Override of BaseApplication::AppInit() virtual method, called by BaseApplication::Init() + * + * @return CHIP_ERROR + */ + CHIP_ERROR AppInit() override; + + /** + * @brief PB0 Button event processing function + * Press and hold will trigger a factory reset timer start + * Press and release will restart BLEAdvertising if not commisionned + * + * @param aEvent button event being processed + */ + static void ButtonHandler(AppEvent * aEvent); +}; diff --git a/examples/rangehood-app/silabs/include/CHIPProjectConfig.h b/examples/rangehood-app/silabs/include/CHIPProjectConfig.h new file mode 100644 index 00000000000..b23f2c243f7 --- /dev/null +++ b/examples/rangehood-app/silabs/include/CHIPProjectConfig.h @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * Copyright (c) 2025 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + * + * 0xFFF1: Test vendor + */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + * + * 0x8005: example Closure app + */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8005 // TODO allocate new product ID + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +/** + * @def CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + * + * @brief + * Active retransmit interval, or time to wait before retransmission after + * subsequent failures in milliseconds. + * + * This is the default value, that might be adjusted by end device depending on its + * needs (e.g. sleeping period) using Service Discovery TXT record CRA key. + * + */ +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL (2000_ms32) diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h new file mode 100644 index 00000000000..b27b3f10f8b --- /dev/null +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -0,0 +1,179 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @class OvenManager + * @brief Manages the initialization and operations related to oven and + * oven panel endpoints in the application. + * + * @note This class is part of the oven application example + */ + +#pragma once + +#include "ExtractorHoodEndpoint.h" +#include "LightEndpoint.h" + +#include "AppEvent.h" + +#include +#include +#include + +class RangeHoodManager +{ +public: + + enum Action_t + { + ON_ACTION = 0, + OFF_ACTION, + + INVALID_ACTION + } Action; + + enum State_t + { + kState_OffInitiated = 0, + kState_OffCompleted, + kState_OnInitiated, + kState_OnCompleted, + } State; + + bool IsLightOn(); + void EnableAutoTurnOff(bool aOn); + void SetAutoTurnOffDuration(uint32_t aDurationInSecs); + bool IsActionInProgress(); + bool InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue); + typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor, uint8_t * value); + typedef void (*Callback_fn_completed)(Action_t); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + + static void OnTriggerOffWithEffect(OnOffEffect * effect); + + /** + * @brief Central handler for delegate requests, Handle the step command from the Fan Control Cluster + */ + void ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff); + + void PercentSettingWriteCallback(uint8_t aNewPercentSetting); + void SpeedSettingWriteCallback(uint8_t aNewSpeedSetting); + void FanModeWriteCallback(FanModeEnum aNewFanMode); + + void SetPercentSetting(Percent aNewPercentSetting); + DataModel::Nullable GetSpeedSetting(); + DataModel::Nullable GetPercentSetting(); + void UpdateFanMode(); + + static void UpdateClusterState(intptr_t arg); + + FanModeEnum GetFanMode(); + void UpdateFanControlLED(); + void UpdateFanControlLCD(); + EndpointId GetEndPoint(); + + /** + * @brief Handle the step command from the Fan Control Cluster + */ + Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; + + struct AttributeUpdateInfo + { + FanModeEnum fanMode; + uint8_t speedCurrent; + uint8_t percentCurrent; + uint8_t speedSetting; + uint8_t percentSetting; + bool isPercentCurrent = false; + bool isSpeedCurrent = false; + bool isSpeedSetting = false; + bool isFanMode = false; + bool isPercentSetting = false; + EndpointId endPoint; + }; + +private: + friend RangeHoodManager & RangehoodMgr(void); + State_t mState; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + bool mAutoTurnOff; + uint32_t mAutoTurnOffDuration; + bool mAutoTurnOffTimerArmed; + bool mOffEffectArmed; + osTimerId_t mLightTimer; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(void * timerCbArg); + static void AutoTurnOffTimerEventHandler(AppEvent * aEvent); + static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + static void OffEffectTimerEventHandler(AppEvent * aEvent); + + EndpointId mEndPoint = FAN_ENDPOINT; + uint8_t mSpeedMax; + + uint8_t percentCurrent; + uint8_t speedCurrent; + + // Fan Mode Limits + static constexpr int kFanModeLowLowerBound = 1; + static constexpr int kFanModeLowUpperBound = 3; + static constexpr int kFanModeMediumLowerBound = 4; + static constexpr int kFanModeMediumUpperBound = 7; + static constexpr int kFanModeHighLowerBound = 8; + static constexpr int kFanModeHighUpperBound = 10; + + static constexpr int kaLowestOffTrue = 0; + static constexpr int kaLowestOffFalse = 1; + + /** + * @brief Initializes the RangeHoodManager and its associated resources. + * + */ + void Init(); + + /** + * @brief Returns the singleton instance of the RangeHoodManager. + * + * @return Reference to the singleton RangeHoodManager instance. + */ + static RangeHoodManager & GetInstance() { return sRangeHoodMgr; } + + static sRangeHoodMgr; + + // FanControlDelegate object + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + // Define the endpoint ID for the RangeHood + static constexpr chip::EndpointId kExtractorHoodEndpoint1 = 1; + static constexpr chip::EndpointId kLightEndpoint1 = 2; + + chip::app::Clusters::ExtractorHood::ExtractorHoodEndpoint mExtractorHoodEndpoint1; + chip::app::Clusters::Light::LightEndpoint mLightEndpoint2; +}; + +inline RangeHoodManager & RangeHoodMgr(void) +{ + return RangeHoodManager::sRangeHoodMgr; +} diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp new file mode 100644 index 00000000000..12905dc1b54 --- /dev/null +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -0,0 +1,176 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" + +#include "LEDWidget.h" + +#ifdef DISPLAY_ENABLED +#include "lcd.h" +#ifdef QR_CODE_ENABLED +#include "qrcodegen.h" +#endif // QR_CODE_ENABLED +#endif // DISPLAY_ENABLED + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include + +#define APP_FUNCTION_BUTTON 0 +#define APP_ACTION_BUTTON 1 + +using namespace chip; +using namespace chip::app; +using namespace chip::TLV; +using namespace ::chip::DeviceLayer; +using namespace chip::app::Clusters::FanControl; +using namespace chip::app::Clusters; + +/********************************************************** + * AppTask Definitions + *********************************************************/ + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::AppInit() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler); + +#ifdef DISPLAY_ENABLED + GetLCD().SetCustomUI(FanControlUI::DrawUI); +#endif + + // Initialization of Oven Manager and endpoints of oven. + RangeHoodManager::GetInstance().Init(); + RangeHoodManager::GetInstance().SetCallbacks(ActionInitiated, ActionCompleted); +// Update the LCD with the Stored value. Show QR Code if not provisioned +#ifdef DISPLAY_ENABLED + GetLCD().WriteDemoUI(false); +#ifdef QR_CODE_ENABLED +#ifdef SL_WIFI + if (!ConnectivityMgr().IsWiFiStationProvisioned()) +#else + if (!ConnectivityMgr().IsThreadProvisioned()) +#endif /* !SL_WIFI */ + { + GetLCD().ShowQRCode(true); + } +#endif // QR_CODE_ENABLED +#endif + + return err; +} + +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + osMessageQueueId_t sAppEventQueue = *(static_cast(pvParameter)); + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "AppTask.Init() failed"); + appError(err); + } + +#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER) + sAppTask.StartStatusLEDTimer(); +#endif + + ChipLogProgress(AppServer, "App Task started"); + + while (true) + { + osStatus_t eventReceived = osMessageQueueGet(sAppEventQueue, &event, NULL, osWaitForever); + while (eventReceived == osOK) + { + sAppTask.DispatchEvent(&event); + eventReceived = osMessageQueueGet(sAppEventQueue, &event, NULL, 0); + } + } +} + +void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) +{ + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Action = btnAction; + button_event.Handler = BaseApplication::ButtonHandler; + AppTask::GetAppTask().PostEvent(&button_event); +} + +void AppTask::ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * aValue) +{ + bool lightOn = aAction == RangeHoodManager::ON_ACTION; + SILABS_LOG("Turning light %s", (lightOn) ? "On" : "Off"); + + // TODO: Update LED state + +#ifdef DISPLAY_ENABLED + sAppTask.GetLCD().WriteDemoUI(lightOn); +#endif + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } +} + +void AppTask::ActionCompleted(RangeHoodManager::Action_t aAction) +{ + // Action has been completed on the Light + if (aAction == RangeHoodManager::ON_ACTION) + { + SILABS_LOG("Light ON"); + } + else if (aAction == RangeHoodManager::OFF_ACTION) + { + SILABS_LOG("Light OFF"); + } + + if (sAppTask.mSyncClusterToButtonAction) + { + // TODO: Schedule work to Update Light Endpoints (turn on/off) + sAppTask.mSyncClusterToButtonAction = false; + } +} diff --git a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp new file mode 100644 index 00000000000..90bc88dc15b --- /dev/null +++ b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements the handler for data model messages. + */ + +#include "AppConfig.h" +#include "AppTask.h" + +#include +#include +#include +#include + +#include "RangeHoodManager.h" + +#include + +using namespace ::chip; +using namespace ::chip::app::Clusters; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + EndpointId endpointId = attributePath.mEndpointId; + + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI " on endpoint %u", ChipLogValueMEI(clusterId), endpointId); + + switch (clusterId) + { + case FanControl::Id: + // Fan control should only be on FAN_ENDPOINT + if (endpointId == FAN_ENDPOINT) + { + RangehoodMgr().HandleFanControlAttributeChange(attributeId, type, size, value); + } + break; + + case OnOff::Id: + // Light on/off control should only be on LIGHT_ENDPOINT + if (endpointId == LIGHT_ENDPOINT && attributeId == OnOff::Attributes::OnOff::Id) + { + RangehoodMgr().InitiateAction(AppEvent::kEventType_Light, *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, + value); + } + break; + + case Identify::Id: + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u on endpoint %u", + ChipLogValueMEI(attributeId), type, *value, size, endpointId); + break; + + default: + ChipLogProgress(Zcl, "Unhandled cluster " ChipLogFormatMEI " on endpoint %u", ChipLogValueMEI(clusterId), endpointId); + break; + } +} diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp new file mode 100644 index 00000000000..bd660d0a5f5 --- /dev/null +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -0,0 +1,561 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RangeHoodManager.h" + +#include "ExtractorHoodEndpoint.h" +#include "LightEndpoint.h" + +#include "AppConfig.h" +#include "AppTask.h" + +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace ::chip::app::Clusters; +using Protocols::InteractionModel::Status; + +RangeHoodManager RangeHoodManager::sRangeHoodMgr; + +void RangeHoodManager::Init() +{ + DeviceLayer::PlatformMgr().LockChipStack(); + // Endpoint initializations + VerifyOrReturn(mExtractorHoodEndpoint1.Init() == CHIP_NO_ERROR, ChipLogError(AppServer, "mExtractorHoodEndpoint1 Init failed")); + + VerifyOrReturn(mLightEndpoint2.Init() == CHIP_NO_ERROR, + ChipLogError(AppServer, "mLightEndpoint2 Init failed")); + + // Create cmsis os sw timer for light timer. + mLightTimer = osTimerNew(TimerEventHandler, // timer callback handler + osTimerOnce, // no timer reload (one-shot timer) + (void *) this, // pass the app task obj context + NULL // No osTimerAttr_t to provide. + ); + + if (mLightTimer == NULL) + { + SILABS_LOG("mLightTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + bool currentLedState; + + // read current on/off value on light endpoint. + chip::DeviceLayer::PlatformMgr().LockChipStack(); + OnOffServer::Instance().getOnOffValue(LIGHT_ENDPOINT, ¤tLedState); + + + Attributes::SpeedMax::Get(GetEndPoint(), &mSpeedMax); + + DataModel::Nullable percentSettingNullable = GetPercentSetting(); + uint8_t percentSettingCB = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value(); + PercentSettingWriteCallback(percentSettingCB); + + DataModel::Nullable speedSettingNullable = GetSpeedSetting(); + uint8_t speedSettingCB = speedSettingNullable.IsNull() ? 0 : speedSettingNullable.Value(); + SpeedSettingWriteCallback(speedSettingCB); + + FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, /* delegate object*/ ); + + DeviceLayer::PlatformMgr().UnlockChipStack(); +} + +bool RangeHoodManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue) +{ + bool action_initiated = false; + State_t new_state; + + // Initiate Turn On/Off Action only when the previous one is complete. + if (((mState == kState_OffCompleted) || mOffEffectArmed) && aAction == ON_ACTION) + { + action_initiated = true; + + new_state = kState_OnInitiated; + if (mOffEffectArmed) + { + CancelTimer(); + mOffEffectArmed = false; + } + } + else if (mState == kState_OnCompleted && aAction == OFF_ACTION && mOffEffectArmed == false) + { + action_initiated = true; + + new_state = kState_OffInitiated; + if (mAutoTurnOffTimerArmed) + { + // If auto turn off timer has been armed and someone initiates turning off, + // cancel the timer and continue as normal. + mAutoTurnOffTimerArmed = false; + + CancelTimer(); + } + } + + if (action_initiated && (aAction == ON_ACTION || aAction == OFF_ACTION)) + { + StartTimer(ACTUATOR_MOVEMENT_PERIOD_MS); + mState = new_state; + } + + if (action_initiated && mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor, aValue); + } + + return action_initiated; +} + +void RangeHoodManager::StartTimer(uint32_t aTimeoutMs) +{ + // Starts or restarts the function timer + if (osTimerStart(mLightTimer, pdMS_TO_TICKS(aTimeoutMs)) != osOK) + { + SILABS_LOG("mLightTimer timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void RangeHoodManager::CancelTimer(void) +{ + if (osTimerStop(mLightTimer) == osError) + { + SILABS_LOG("mLightTimer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } +} + +void RangeHoodManager::TimerEventHandler(void * timerCbArg) +{ + // The callback argument is the light obj context assigned at timer creation. + RangeHoodManager * light = static_cast(timerCbArg); + + // The timer event handler will be called in the context of the timer task + // once mLightTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = light; + if (light->mAutoTurnOffTimerArmed) + { + event.Handler = AutoTurnOffTimerEventHandler; + } + else if (light->mOffEffectArmed) + { + event.Handler = OffEffectTimerEventHandler; + } + else + { + event.Handler = ActuatorMovementTimerEventHandler; + } + AppTask::GetAppTask().PostEvent(&event); +} + +void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = AppEvent::kEventType_Timer; + uint8_t value = aEvent->LightEvent.Value; + + // Make sure auto turn off timer is still armed. + if (!light->mAutoTurnOffTimerArmed) + { + return; + } + + light->mAutoTurnOffTimerArmed = false; + + SILABS_LOG("Auto Turn Off has been triggered!"); + + light->InitiateAction(actor, OFF_ACTION, &value); +} + +void RangeHoodManager::OffEffectTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = AppEvent::kEventType_Timer; + uint8_t value = aEvent->LightEvent.Value; + + // Make sure auto turn off timer is still armed. + if (!light->mOffEffectArmed) + { + return; + } + + light->mOffEffectArmed = false; + + SILABS_LOG("OffEffect completed"); + + light->InitiateAction(actor, OFF_ACTION, &value); +} + +void RangeHoodManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action_t actionCompleted = INVALID_ACTION; + + RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); + + if (light->mState == kState_OffInitiated) + { + light->mState = kState_OffCompleted; + actionCompleted = OFF_ACTION; + } + else if (light->mState == kState_OnInitiated) + { + light->mState = kState_OnCompleted; + actionCompleted = ON_ACTION; + } + + if (actionCompleted != INVALID_ACTION) + { + if (light->mActionCompleted_CB) + { + light->mActionCompleted_CB(actionCompleted); + } + + if (light->mAutoTurnOff && actionCompleted == ON_ACTION) + { + // Start the timer for auto turn off + light->StartTimer(light->mAutoTurnOffDuration * 1000); + + light->mAutoTurnOffTimerArmed = true; + + SILABS_LOG("Auto Turn off enabled. Will be triggered in %u seconds", light->mAutoTurnOffDuration); + } + } +} + +void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) +{ + auto effectId = effect->mEffectIdentifier; + auto effectVariant = effect->mEffectVariant; + uint32_t offEffectDuration = 0; + + // Temporary print outs and delay to test OffEffect behaviour + // Until dimming is supported for dev boards. + if (effectId == EffectIdentifierEnum::kDelayedAllOff) + { + auto typedEffectVariant = static_cast(effectVariant); + if (typedEffectVariant == DelayedAllOffEffectVariantEnum::kDelayedOffFastFade) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "DelayedAllOffEffectVariantEnum::kDelayedOffFastFade"); + } + else if (typedEffectVariant == DelayedAllOffEffectVariantEnum::kNoFade) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "DelayedAllOffEffectVariantEnum::kNoFade"); + } + else if (typedEffectVariant == DelayedAllOffEffectVariantEnum::kDelayedOffSlowFade) + { + offEffectDuration = 12800; + ChipLogProgress(Zcl, "DelayedAllOffEffectVariantEnum::kDelayedOffSlowFade"); + } + } + else if (effectId == EffectIdentifierEnum::kDyingLight) + { + auto typedEffectVariant = static_cast(effectVariant); + if (typedEffectVariant == DyingLightEffectVariantEnum::kDyingLightFadeOff) + { + offEffectDuration = 1500; + ChipLogProgress(Zcl, "DyingLightEffectVariantEnum::kDyingLightFadeOff"); + } + } + + LightMgr().mOffEffectArmed = true; + LightMgr().StartTimer(offEffectDuration); +} + +Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) +{ + ChipLogProgress(AppServer, "RangeHoodManager::ProcessExtractorStepCommand ep=%u aDirection %d, aWrap %d, aLowestOff %d", endpointId, to_underlying(aDirection), + aWrap, aLowestOff); + + VerifyOrReturnError(aDirection != StepDirectionEnum::kUnknownEnumValue, Status::InvalidCommand); + + // if aLowestOff is true, Step command can reduce the fan speed to 0, else 1. + uint8_t speedMin = aLowestOff ? kaLowestOffTrue : kaLowestOffFalse; + + DataModel::Nullable speedSettingNullable = GetSpeedSetting(); + + uint8_t curSpeedSetting = speedSettingNullable.IsNull() ? speedMin : speedSettingNullable.Value(); + + // increase or decrease the fan speed by one step + switch (aDirection) + { + case StepDirectionEnum::kIncrease: { + if (curSpeedSetting >= mSpeedMax) + { + curSpeedSetting = aWrap ? speedMin : mSpeedMax; + } + else + { + curSpeedSetting++; + } + break; + } + case StepDirectionEnum::kDecrease: { + if (curSpeedSetting <= speedMin) + { + curSpeedSetting = aWrap ? mSpeedMax : speedMin; + } + else + { + curSpeedSetting--; + } + break; + } + default: { + break; + } + } + + // Convert SpeedSetting to PercentSetting + uint8_t curPercentSetting = ((static_cast(curSpeedSetting) * 100) / mSpeedMax); + + AttributeUpdateInfo * data = chip::Platform::New(); + data->percentSetting = curPercentSetting; + data->endPoint = GetEndPoint(); + data->isPercentSetting = true; + + if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "FanControlManager::HandleStep: Failed to update PercentSetting attribute"); + return Status::Failure; + } + + return Status::Success; +} + +void RangeHoodManager::UpdateClusterState(intptr_t arg) +{ + RangeHoodManager::AttributeUpdateInfo * data = reinterpret_cast(arg); + if (data->isSpeedCurrent) + { + Attributes::SpeedCurrent::Set(data->endPoint, data->speedCurrent); + } + else if (data->isPercentCurrent) + { + Attributes::PercentCurrent::Set(data->endPoint, data->percentCurrent); + } + else if (data->isSpeedSetting) + { + Attributes::SpeedSetting::Set(data->endPoint, data->speedSetting); + } + else if (data->isFanMode) + { + Attributes::FanMode::Set(data->endPoint, data->fanMode); + } + else if (data->isPercentSetting) + { + Attributes::PercentSetting::Set(data->endPoint, data->percentSetting); + } + chip::Platform::Delete(data); +} + +void RangeHoodManager::HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value) +{ + switch (attributeId) + { + case Attributes::PercentSetting::Id: { + PercentSettingWriteCallback(*value); + break; + } + + case Attributes::SpeedSetting::Id: { + SpeedSettingWriteCallback(*value); + break; + } + + case Attributes::FanMode::Id: { + mFanMode = *reinterpret_cast(value); + FanModeWriteCallback(mFanMode); + break; + } + + default: { + break; + } + } +} + +void RangeHoodManager::PercentSettingWriteCallback(uint8_t aNewPercentSetting) +{ + VerifyOrReturn(aNewPercentSetting != percentCurrent); + VerifyOrReturn(mFanMode != FanModeEnum::kAuto); + ChipLogDetail(NotSpecified, "RangeHoodManager::PercentSettingWriteCallback: %d", aNewPercentSetting); + percentCurrent = aNewPercentSetting; + + AttributeUpdateInfo * data = chip::Platform::New(); + data->endPoint = GetEndPoint(); + data->percentCurrent = percentCurrent; + data->isPercentCurrent = true; + + if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "RangeHoodManager::PercentSettingWriteCallback: failed to set PercentCurrent attribute"); + } +} + +void RangeHoodManager::SpeedSettingWriteCallback(uint8_t aNewSpeedSetting) +{ + VerifyOrReturn(aNewSpeedSetting != speedCurrent); + VerifyOrReturn(mFanMode != FanModeEnum::kAuto); + ChipLogDetail(NotSpecified, "RangeHoodManager::SpeedSettingWriteCallback: %d", aNewSpeedSetting); + speedCurrent = aNewSpeedSetting; + + AttributeUpdateInfo * data = chip::Platform::New(); + data->endPoint = GetEndPoint(); + data->speedCurrent = speedCurrent; + data->isSpeedCurrent = true; + + if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "RangeHoodManager::SpeedSettingWriteCallback: failed to set SpeedCurrent attribute"); + } + + // Update the fan mode as per the current speed. + if (speedCurrent == 0) + { + mFanMode = FanModeEnum::kOff; + } + else if (speedCurrent <= kFanModeLowUpperBound) + { + mFanMode = FanModeEnum::kLow; + } + else if (speedCurrent <= kFanModeMediumUpperBound) + { + mFanMode = FanModeEnum::kMedium; + } + else if (speedCurrent <= kFanModeHighUpperBound) + { + mFanMode = FanModeEnum::kHigh; + } + UpdateFanMode(); +} + +void RangeHoodManager::UpdateFanMode() +{ + AttributeUpdateInfo * data = chip::Platform::New(); + data->endPoint = GetEndPoint(); + data->fanMode = mFanMode; + data->isFanMode = true; + if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "RangeHoodManager::UpdateFanMode: failed to update FanMode attribute"); + } +} + +void RangeHoodManager::FanModeWriteCallback(FanModeEnum aNewFanMode) +{ + ChipLogDetail(NotSpecified, "FanControlManager::FanModeWriteCallback: %d", (uint8_t) aNewFanMode); + // Set Percent Settings, which will update the Speed Settings through callback. + switch (aNewFanMode) + { + case FanModeEnum::kOff: { + if (speedCurrent != 0) + { + Percent percentSetting = 0; + SetPercentSetting(percentSetting); + } + break; + } + case FanModeEnum::kLow: { + if (speedCurrent < kFanModeLowLowerBound || speedCurrent > kFanModeLowUpperBound) + { + Percent percentSetting = kFanModeLowUpperBound * mSpeedMax; + SetPercentSetting(percentSetting); + } + break; + } + case FanModeEnum::kMedium: { + if (speedCurrent < kFanModeMediumLowerBound || speedCurrent > kFanModeMediumUpperBound) + { + Percent percentSetting = kFanModeMediumLowerBound * mSpeedMax; + SetPercentSetting(percentSetting); + } + break; + } + case FanModeEnum::kOn: + case FanModeEnum::kHigh: { + if (speedCurrent < kFanModeHighLowerBound || speedCurrent > kFanModeHighUpperBound) + { + Percent percentSetting = kFanModeHighLowerBound * mSpeedMax; + SetPercentSetting(percentSetting); + } + break; + } + case FanModeEnum::kSmart: + case FanModeEnum::kAuto: { + UpdateFanMode(); + break; + } + case FanModeEnum::kUnknownEnumValue: { + ChipLogProgress(NotSpecified, "RangeHoodManager::FanModeWriteCallback: Unknown"); + break; + } + default: + break; + } +} + +void RangeHoodManager::SetPercentSetting(Percent aNewPercentSetting) +{ + if (aNewPercentSetting != percentCurrent) + { + AttributeUpdateInfo * data = chip::Platform::New(); + data->percentCurrent = aNewPercentSetting; + data->endPoint = GetEndPoint(); + data->isPercentCurrent = true; + if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "RangeHoodManager::SetPercentSetting: failed to update PercentSetting attribute"); + } + } +} + +DataModel::Nullable RangeHoodManager::GetSpeedSetting() +{ + DataModel::Nullable speedSetting; + + Status status = Attributes::SpeedSetting::Get(GetEndPoint(), speedSetting); + if (status != Status::Success) + { + ChipLogError(NotSpecified, "RangeHoodManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", + to_underlying(status)); + } + + return speedSetting; +} + +DataModel::Nullable RangeHoodManager::GetPercentSetting() +{ + DataModel::Nullable percentSetting; + + Status status = Attributes::PercentSetting::Get(GetEndPoint(), percentSetting); + if (status != Status::Success) + { + ChipLogError(NotSpecified, "RangeHoodManager::GetPercentSetting: failed to get PercentSetting attribute: %d", + to_underlying(status)); + } + + return percentSetting; +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/third_party/connectedhomeip b/examples/rangehood-app/silabs/third_party/connectedhomeip new file mode 120000 index 00000000000..c866b868749 --- /dev/null +++ b/examples/rangehood-app/silabs/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file From d1ba54b38074a9ba24b90bdd5269ed6a2e7caff1 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Mon, 27 Oct 2025 22:40:23 +0530 Subject: [PATCH 02/11] Cleanedup rangehoodapp --- .../include/ExtractorHoodEndpoint.h | 8 +++- .../include/LightEndpoint.h | 1 - examples/rangehood-app/silabs/BUILD.gn | 8 ++-- .../rangehood-app/silabs/include/AppTask.h | 2 + .../silabs/include/RangeHoodManager.h | 2 +- examples/rangehood-app/silabs/src/AppTask.cpp | 17 +++++--- .../silabs/src/RangeHoodManager.cpp | 41 +++++++++---------- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h index 86d59e559b6..9104f549424 100644 --- a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -52,7 +52,7 @@ class FanDelegate : public FanControl::Delegate protected: EndpointId mEndpoint = 0; -} +}; class ExtractorHoodEndpoint { @@ -64,10 +64,16 @@ class ExtractorHoodEndpoint */ CHIP_ERROR Init(); + /** + * @brief Get the FanDelegate instance for this endpoint. + */ + FanDelegate & GetFanDelegate() { return mFanDelegate; } + /* Add ExtractorHoodEndpoint functions*/ private: EndpointId mEndpointId = kInvalidEndpointId; + FanDelegate mFanDelegate; }; } // namespace ExtractorHood diff --git a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h index 1ff4624c47a..750552a4b3e 100644 --- a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h @@ -48,7 +48,6 @@ class LightEndpoint void SetOnOffState(bool state); private: - bool currentOnOffState = false; EndpointId mEndpointId = kInvalidEndpointId; }; diff --git a/examples/rangehood-app/silabs/BUILD.gn b/examples/rangehood-app/silabs/BUILD.gn index 523f61263db..8372348b610 100644 --- a/examples/rangehood-app/silabs/BUILD.gn +++ b/examples/rangehood-app/silabs/BUILD.gn @@ -35,10 +35,10 @@ silabs_project_dir = "${chip_root}/examples/rangehood-app/silabs" examples_common_plat_dir = "${chip_root}/examples/platform/silabs" example_rangehood_dir = "${chip_root}/examples/rangehood-app" -if (wifi_soc) { +#if (wifi_soc) { import("${chip_root}/third_party/silabs/SiWx917_sdk.gni") examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917" -} +#} import("${examples_common_plat_dir}/args.gni") @@ -106,7 +106,7 @@ silabs_executable("rangehood_app") { "${examples_common_plat_dir}/main.cpp", "src/AppTask.cpp", "src/DataModelCallbacks.cpp", - "src/RangehoodManager.cpp", + "src/RangeHoodManager.cpp", ] deps = [ ":sdk" ] @@ -187,7 +187,7 @@ silabs_executable("rangehood_app") { } group("silabs") { - deps = [ ":oven_app" ] + deps = [ ":rangehood_app" ] } group("default") { diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h index c7aa1493ad0..5e87883f5ab 100644 --- a/examples/rangehood-app/silabs/include/AppTask.h +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -77,6 +77,7 @@ class AppTask : public BaseApplication * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED */ static void ButtonEventHandler(uint8_t button, uint8_t btnAction); + void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); private: static AppTask sAppTask; @@ -84,6 +85,7 @@ class AppTask : public BaseApplication static void ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * value); static void ActionCompleted(RangeHoodManager::Action_t aAction); + static void LightActionEventHandler(AppEvent * aEvent); /** * @brief Override of BaseApplication::AppInit() virtual method, called by BaseApplication::Init() * diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index b27b3f10f8b..467709f8833 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -149,7 +149,7 @@ class RangeHoodManager * @brief Initializes the RangeHoodManager and its associated resources. * */ - void Init(); + CHIP_ERROR Init(); /** * @brief Returns the singleton instance of the RangeHoodManager. diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp index 12905dc1b54..f85f0ce8a5d 100644 --- a/examples/rangehood-app/silabs/src/AppTask.cpp +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -30,7 +30,7 @@ #endif // QR_CODE_ENABLED #endif // DISPLAY_ENABLED -#include +#include "RangeHoodManager.h" #include #include #include @@ -71,13 +71,10 @@ CHIP_ERROR AppTask::AppInit() CHIP_ERROR err = CHIP_NO_ERROR; chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler); -#ifdef DISPLAY_ENABLED - GetLCD().SetCustomUI(FanControlUI::DrawUI); -#endif - // Initialization of Oven Manager and endpoints of oven. RangeHoodManager::GetInstance().Init(); RangeHoodManager::GetInstance().SetCallbacks(ActionInitiated, ActionCompleted); + // Update the LCD with the Stored value. Show QR Code if not provisioned #ifdef DISPLAY_ENABLED GetLCD().WriteDemoUI(false); @@ -174,3 +171,13 @@ void AppTask::ActionCompleted(RangeHoodManager::Action_t aAction) sAppTask.mSyncClusterToButtonAction = false; } } + +void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Light; + event.LightEvent.Actor = aActor; + event.LightEvent.Action = aAction; + event.Handler = LightActionEventHandler; + PostEvent(&event); +} diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index bd660d0a5f5..16e09c7e642 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -34,7 +34,7 @@ using Protocols::InteractionModel::Status; RangeHoodManager RangeHoodManager::sRangeHoodMgr; -void RangeHoodManager::Init() +CHIP_ERROR RangeHoodManager::Init() { DeviceLayer::PlatformMgr().LockChipStack(); // Endpoint initializations @@ -63,7 +63,7 @@ void RangeHoodManager::Init() OnOffServer::Instance().getOnOffValue(LIGHT_ENDPOINT, ¤tLedState); - Attributes::SpeedMax::Get(GetEndPoint(), &mSpeedMax); + Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); DataModel::Nullable percentSettingNullable = GetPercentSetting(); uint8_t percentSettingCB = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value(); @@ -73,9 +73,11 @@ void RangeHoodManager::Init() uint8_t speedSettingCB = speedSettingNullable.IsNull() ? 0 : speedSettingNullable.Value(); SpeedSettingWriteCallback(speedSettingCB); - FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, /* delegate object*/ ); + FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, &mExtractorHoodEndpoint1.GetFanDelegate()); DeviceLayer::PlatformMgr().UnlockChipStack(); + + return CHIP_NO_ERROR; } bool RangeHoodManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue) @@ -146,7 +148,7 @@ void RangeHoodManager::CancelTimer(void) void RangeHoodManager::TimerEventHandler(void * timerCbArg) { // The callback argument is the light obj context assigned at timer creation. - RangeHoodManager * light = static_cast(timerCbArg); + RangeHoodManager * light = static_cast(timerCbArg); // The timer event handler will be called in the context of the timer task // once mLightTimer expires. Post an event to apptask queue with the actual handler @@ -171,7 +173,7 @@ void RangeHoodManager::TimerEventHandler(void * timerCbArg) void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) { - LightingManager * light = static_cast(aEvent->TimerEvent.Context); + RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); int32_t actor = AppEvent::kEventType_Timer; uint8_t value = aEvent->LightEvent.Value; @@ -190,7 +192,7 @@ void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) void RangeHoodManager::OffEffectTimerEventHandler(AppEvent * aEvent) { - LightingManager * light = static_cast(aEvent->TimerEvent.Context); + RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); int32_t actor = AppEvent::kEventType_Timer; uint8_t value = aEvent->LightEvent.Value; @@ -280,8 +282,8 @@ void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) } } - LightMgr().mOffEffectArmed = true; - LightMgr().StartTimer(offEffectDuration); + this->mOffEffectArmed = true; + this->StartTimer(offEffectDuration); } Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) @@ -333,12 +335,12 @@ Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId AttributeUpdateInfo * data = chip::Platform::New(); data->percentSetting = curPercentSetting; - data->endPoint = GetEndPoint(); + data->endPoint = kExtractorHoodEndpoint1; data->isPercentSetting = true; if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) { - ChipLogError(NotSpecified, "FanControlManager::HandleStep: Failed to update PercentSetting attribute"); + ChipLogError(NotSpecified, "RangeHoodManager::HandleStep: Failed to update PercentSetting attribute"); return Status::Failure; } @@ -380,11 +382,6 @@ void RangeHoodManager::HandleFanControlAttributeChange(AttributeId attributeId, break; } - case Attributes::SpeedSetting::Id: { - SpeedSettingWriteCallback(*value); - break; - } - case Attributes::FanMode::Id: { mFanMode = *reinterpret_cast(value); FanModeWriteCallback(mFanMode); @@ -405,7 +402,7 @@ void RangeHoodManager::PercentSettingWriteCallback(uint8_t aNewPercentSetting) percentCurrent = aNewPercentSetting; AttributeUpdateInfo * data = chip::Platform::New(); - data->endPoint = GetEndPoint(); + data->endPoint = kExtractorHoodEndpoint1; data->percentCurrent = percentCurrent; data->isPercentCurrent = true; @@ -423,7 +420,7 @@ void RangeHoodManager::SpeedSettingWriteCallback(uint8_t aNewSpeedSetting) speedCurrent = aNewSpeedSetting; AttributeUpdateInfo * data = chip::Platform::New(); - data->endPoint = GetEndPoint(); + data->endPoint = kExtractorHoodEndpoint1; data->speedCurrent = speedCurrent; data->isSpeedCurrent = true; @@ -455,7 +452,7 @@ void RangeHoodManager::SpeedSettingWriteCallback(uint8_t aNewSpeedSetting) void RangeHoodManager::UpdateFanMode() { AttributeUpdateInfo * data = chip::Platform::New(); - data->endPoint = GetEndPoint(); + data->endPoint = kExtractorHoodEndpoint1; data->fanMode = mFanMode; data->isFanMode = true; if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) @@ -466,7 +463,7 @@ void RangeHoodManager::UpdateFanMode() void RangeHoodManager::FanModeWriteCallback(FanModeEnum aNewFanMode) { - ChipLogDetail(NotSpecified, "FanControlManager::FanModeWriteCallback: %d", (uint8_t) aNewFanMode); + ChipLogDetail(NotSpecified, "RangeHoodManager::FanModeWriteCallback: %d", (uint8_t) aNewFanMode); // Set Percent Settings, which will update the Speed Settings through callback. switch (aNewFanMode) { @@ -523,7 +520,7 @@ void RangeHoodManager::SetPercentSetting(Percent aNewPercentSetting) { AttributeUpdateInfo * data = chip::Platform::New(); data->percentCurrent = aNewPercentSetting; - data->endPoint = GetEndPoint(); + data->endPoint = kExtractorHoodEndpoint1; data->isPercentCurrent = true; if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) { @@ -536,7 +533,7 @@ DataModel::Nullable RangeHoodManager::GetSpeedSetting() { DataModel::Nullable speedSetting; - Status status = Attributes::SpeedSetting::Get(GetEndPoint(), speedSetting); + Status status = Attributes::SpeedSetting::Get(kExtractorHoodEndpoint1, speedSetting); if (status != Status::Success) { ChipLogError(NotSpecified, "RangeHoodManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", @@ -550,7 +547,7 @@ DataModel::Nullable RangeHoodManager::GetPercentSetting() { DataModel::Nullable percentSetting; - Status status = Attributes::PercentSetting::Get(GetEndPoint(), percentSetting); + Status status = Attributes::PercentSetting::Get(kExtractorHoodEndpoint1, percentSetting); if (status != Status::Success) { ChipLogError(NotSpecified, "RangeHoodManager::GetPercentSetting: failed to get PercentSetting attribute: %d", From 198abade4024c6e3e779cbd4950724c1cd26f38d Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Tue, 28 Oct 2025 11:40:34 +0530 Subject: [PATCH 03/11] Resolved build errors --- .../include/ExtractorHoodEndpoint.h | 14 +++-- .../include/LightEndpoint.h | 3 +- .../src/LightEndpoint.cpp | 5 -- .../silabs/build_for_wifi_args.gni | 2 +- .../rangehood-app/silabs/include/AppConfig.h | 4 -- .../rangehood-app/silabs/include/AppEvent.h | 1 + .../rangehood-app/silabs/include/AppTask.h | 4 +- .../silabs/include/RangeHoodManager.h | 63 ++++++++++--------- examples/rangehood-app/silabs/src/AppTask.cpp | 20 +++--- .../silabs/src/DataModelCallbacks.cpp | 12 +--- .../silabs/src/RangeHoodManager.cpp | 39 ++++++------ 11 files changed, 87 insertions(+), 80 deletions(-) diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h index 9104f549424..5aa89974887 100644 --- a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -1,4 +1,3 @@ - GNU nano 6.2 ExtractorHoodEndpoint.h /* * * Copyright (c) 2024 Project CHIP Authors @@ -27,11 +26,15 @@ #include #include +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::FanControl; +using Protocols::InteractionModel::Status; + namespace chip { namespace app { namespace Clusters { -namespace ExtractorHood { - +namespace FanDelegate { class FanDelegate : public FanControl::Delegate { public: @@ -46,14 +49,15 @@ class FanDelegate : public FanControl::Delegate * @return Success On success. * @return Other Value indicating it failed to execute the command. */ - Protocols::InteractionModel::Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; + Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; FanDelegate(EndpointId aEndpoint) : mEndpoint(aEndpoint) {} protected: EndpointId mEndpoint = 0; }; - +} // namespace FanDelegate +namespace ExtractorHood { class ExtractorHoodEndpoint { public: diff --git a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h index 750552a4b3e..ab4286b393f 100644 --- a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h @@ -1,4 +1,3 @@ -@@ -0,0 +1,52 @@ /* * * Copyright (c) 2025 Project CHIP Authors @@ -30,7 +29,7 @@ namespace Light { class LightEndpoint { public: - LightEndpoint(EndpointId endpointId) : mEndpointId(endpointId) {} + LightEndpoint() {} /** * @brief Initialize the Light endpoint. diff --git a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp index 98705d7631c..4cc6cb5a381 100644 --- a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp @@ -25,11 +25,6 @@ using namespace chip; using namespace chip::app::Clusters::Light; -CHIP_ERROR LightEndpoint::Init() -{ - return CHIP_NO_ERROR; -} - CHIP_ERROR LightEndpoint::Init() { bool state = false; diff --git a/examples/rangehood-app/silabs/build_for_wifi_args.gni b/examples/rangehood-app/silabs/build_for_wifi_args.gni index 300108d01cc..50ffa4e778a 100644 --- a/examples/rangehood-app/silabs/build_for_wifi_args.gni +++ b/examples/rangehood-app/silabs/build_for_wifi_args.gni @@ -19,4 +19,4 @@ import("${chip_root}/src/platform/silabs/wifi/args.gni") sl_enable_test_event_trigger = false chip_enable_ota_requestor = false -app_data_model = "${chip_root}/examples/rangehood-app-common/rangehood-app-common" +app_data_model = "${chip_root}/examples/rangehood-app/rangehood-app-common" diff --git a/examples/rangehood-app/silabs/include/AppConfig.h b/examples/rangehood-app/silabs/include/AppConfig.h index 422336f7be0..dff6ee6236f 100644 --- a/examples/rangehood-app/silabs/include/AppConfig.h +++ b/examples/rangehood-app/silabs/include/AppConfig.h @@ -30,7 +30,3 @@ // Time it takes in ms for the simulated actuator to move from one // state to another. #define ACTUATOR_MOVEMENT_PERIOD_MS 10 - -// Endpoint definitions for rangehood app -#define FAN_ENDPOINT 1 -#define LIGHT_ENDPOINT 2 \ No newline at end of file diff --git a/examples/rangehood-app/silabs/include/AppEvent.h b/examples/rangehood-app/silabs/include/AppEvent.h index f5fb64ccfc9..02954cf10e4 100644 --- a/examples/rangehood-app/silabs/include/AppEvent.h +++ b/examples/rangehood-app/silabs/include/AppEvent.h @@ -35,6 +35,7 @@ struct AppEvent : public BaseAppEvent { uint8_t Action; int32_t Actor; + uint8_t Value; } RangeHoodEvent; }; }; diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h index 5e87883f5ab..5e8032ee827 100644 --- a/examples/rangehood-app/silabs/include/AppTask.h +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -35,6 +35,8 @@ #include #include +#include "RangeHoodManager.h" + /********************************************************** * Defines *********************************************************/ @@ -77,7 +79,7 @@ class AppTask : public BaseApplication * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED */ static void ButtonEventHandler(uint8_t button, uint8_t btnAction); - void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); + void PostLightActionRequest(int32_t aActor, RangeHoodManager::Action_t aAction); private: static AppTask sAppTask; diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index 467709f8833..4fec8862bb8 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -33,8 +33,17 @@ #include #include +#include + #include +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::FanControl; +using chip::Percent; +using chip::EndpointId; +using Protocols::InteractionModel::Status; + class RangeHoodManager { public: @@ -69,15 +78,17 @@ class RangeHoodManager /** * @brief Central handler for delegate requests, Handle the step command from the Fan Control Cluster */ - void ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff); + Status ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff); + + void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value); void PercentSettingWriteCallback(uint8_t aNewPercentSetting); void SpeedSettingWriteCallback(uint8_t aNewSpeedSetting); void FanModeWriteCallback(FanModeEnum aNewFanMode); void SetPercentSetting(Percent aNewPercentSetting); - DataModel::Nullable GetSpeedSetting(); - DataModel::Nullable GetPercentSetting(); + // DataModel::Nullable GetSpeedSetting(); + // DataModel::Nullable GetPercentSetting(); void UpdateFanMode(); static void UpdateClusterState(intptr_t arg); @@ -87,12 +98,7 @@ class RangeHoodManager void UpdateFanControlLCD(); EndpointId GetEndPoint(); - /** - * @brief Handle the step command from the Fan Control Cluster - */ - Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; - - struct AttributeUpdateInfo + struct AttributeUpdateInfo { FanModeEnum fanMode; uint8_t speedCurrent; @@ -107,8 +113,23 @@ class RangeHoodManager EndpointId endPoint; }; + /** + * @brief Returns the singleton instance of the RangeHoodManager. + * + * @return Reference to the singleton RangeHoodManager instance. + */ + static RangeHoodManager & GetInstance() { return sRangeHoodMgr; } + + /** + * @brief Initializes the RangeHoodManager and its associated resources. + * + */ + CHIP_ERROR Init(); + + // ...existing public methods... + private: - friend RangeHoodManager & RangehoodMgr(void); + friend RangeHoodManager & RangeHoodMgr(void); State_t mState; Callback_fn_initiated mActionInitiated_CB; @@ -128,9 +149,8 @@ class RangeHoodManager static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); static void OffEffectTimerEventHandler(AppEvent * aEvent); - EndpointId mEndPoint = FAN_ENDPOINT; + FanModeEnum mFanMode; uint8_t mSpeedMax; - uint8_t percentCurrent; uint8_t speedCurrent; @@ -145,26 +165,13 @@ class RangeHoodManager static constexpr int kaLowestOffTrue = 0; static constexpr int kaLowestOffFalse = 1; - /** - * @brief Initializes the RangeHoodManager and its associated resources. - * - */ - CHIP_ERROR Init(); - - /** - * @brief Returns the singleton instance of the RangeHoodManager. - * - * @return Reference to the singleton RangeHoodManager instance. - */ - static RangeHoodManager & GetInstance() { return sRangeHoodMgr; } + DataModel::Nullable GetPercentSetting(); + DataModel::Nullable GetSpeedSetting(); - static sRangeHoodMgr; + static RangeHoodManager sRangeHoodMgr; // FanControlDelegate object - Callback_fn_initiated mActionInitiated_CB; - Callback_fn_completed mActionCompleted_CB; - // Define the endpoint ID for the RangeHood static constexpr chip::EndpointId kExtractorHoodEndpoint1 = 1; static constexpr chip::EndpointId kLightEndpoint1 = 2; diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp index f85f0ce8a5d..13b0a6bca57 100644 --- a/examples/rangehood-app/silabs/src/AppTask.cpp +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -50,6 +50,8 @@ #include +#define LIGHT_LED 1 + #define APP_FUNCTION_BUTTON 0 #define APP_ACTION_BUTTON 1 @@ -60,6 +62,8 @@ using namespace ::chip::DeviceLayer; using namespace chip::app::Clusters::FanControl; using namespace chip::app::Clusters; +LEDWidget sLightLED; // Use LEDWidget for basic LED functionality + /********************************************************** * AppTask Definitions *********************************************************/ @@ -89,6 +93,8 @@ CHIP_ERROR AppTask::AppInit() } #endif // QR_CODE_ENABLED #endif + sLightLED.Init(LIGHT_LED); + sLightLED.Set(RangeHoodMgr().IsLightOn()); return err; } @@ -141,10 +147,10 @@ void AppTask::ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor bool lightOn = aAction == RangeHoodManager::ON_ACTION; SILABS_LOG("Turning light %s", (lightOn) ? "On" : "Off"); - // TODO: Update LED state + sLightLED.Set(lightOn); #ifdef DISPLAY_ENABLED - sAppTask.GetLCD().WriteDemoUI(lightOn); + sAppTask.GetLCD().WriteDemoUI(lightOn); #endif if (aActor == AppEvent::kEventType_Button) @@ -172,12 +178,12 @@ void AppTask::ActionCompleted(RangeHoodManager::Action_t aAction) } } -void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction) +void AppTask::PostLightActionRequest(int32_t aActor, RangeHoodManager::Action_t aAction) { AppEvent event; - event.Type = AppEvent::kEventType_Light; - event.LightEvent.Actor = aActor; - event.LightEvent.Action = aAction; - event.Handler = LightActionEventHandler; + event.Type = AppEvent::kEventType_RangeHood; + event.RangeHoodEvent.Actor = aActor; + event.RangeHoodEvent.Action = aAction; + // event.Handler = LightActionEventHandler; PostEvent(&event); } diff --git a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp index 90bc88dc15b..85d6d51ab5e 100644 --- a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp +++ b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp @@ -47,20 +47,14 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & switch (clusterId) { case FanControl::Id: - // Fan control should only be on FAN_ENDPOINT - if (endpointId == FAN_ENDPOINT) - { - RangehoodMgr().HandleFanControlAttributeChange(attributeId, type, size, value); - } + // Fan control should only be on FAN ENDPOINT + RangeHoodMgr().HandleFanControlAttributeChange(attributeId, type, size, value); break; case OnOff::Id: // Light on/off control should only be on LIGHT_ENDPOINT - if (endpointId == LIGHT_ENDPOINT && attributeId == OnOff::Attributes::OnOff::Id) - { - RangehoodMgr().InitiateAction(AppEvent::kEventType_Light, *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, + RangeHoodMgr().InitiateAction(AppEvent::kEventType_RangeHood, *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, value); - } break; case Identify::Id: diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index 16e09c7e642..ba4295c7213 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -30,7 +30,11 @@ using namespace chip; using namespace chip::app; using namespace ::chip::app::Clusters; +using namespace ::chip::app::Clusters::FanControl; + +using namespace ::chip::app::Clusters::OnOff; using Protocols::InteractionModel::Status; +using namespace ::chip::DeviceLayer; RangeHoodManager RangeHoodManager::sRangeHoodMgr; @@ -38,10 +42,9 @@ CHIP_ERROR RangeHoodManager::Init() { DeviceLayer::PlatformMgr().LockChipStack(); // Endpoint initializations - VerifyOrReturn(mExtractorHoodEndpoint1.Init() == CHIP_NO_ERROR, ChipLogError(AppServer, "mExtractorHoodEndpoint1 Init failed")); + VerifyOrReturnError(mExtractorHoodEndpoint1.Init() == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); - VerifyOrReturn(mLightEndpoint2.Init() == CHIP_NO_ERROR, - ChipLogError(AppServer, "mLightEndpoint2 Init failed")); + VerifyOrReturnError(mLightEndpoint2.Init() == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); // Create cmsis os sw timer for light timer. mLightTimer = osTimerNew(TimerEventHandler, // timer callback handler @@ -60,10 +63,10 @@ CHIP_ERROR RangeHoodManager::Init() // read current on/off value on light endpoint. chip::DeviceLayer::PlatformMgr().LockChipStack(); - OnOffServer::Instance().getOnOffValue(LIGHT_ENDPOINT, ¤tLedState); + OnOffServer::Instance().getOnOffValue(kLightEndpoint1, ¤tLedState); - Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); + chip::app::Clusters::FanControl::Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); DataModel::Nullable percentSettingNullable = GetPercentSetting(); uint8_t percentSettingCB = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value(); @@ -175,7 +178,7 @@ void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) { RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); int32_t actor = AppEvent::kEventType_Timer; - uint8_t value = aEvent->LightEvent.Value; + uint8_t value = aEvent->RangeHoodEvent.Value; // Make sure auto turn off timer is still armed. if (!light->mAutoTurnOffTimerArmed) @@ -194,7 +197,7 @@ void RangeHoodManager::OffEffectTimerEventHandler(AppEvent * aEvent) { RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); int32_t actor = AppEvent::kEventType_Timer; - uint8_t value = aEvent->LightEvent.Value; + uint8_t value = aEvent->RangeHoodEvent.Value; // Make sure auto turn off timer is still armed. if (!light->mOffEffectArmed) @@ -282,8 +285,8 @@ void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) } } - this->mOffEffectArmed = true; - this->StartTimer(offEffectDuration); + sRangeHoodMgr->mOffEffectArmed = true; + sRangeHoodMgr->StartTimer(offEffectDuration); } Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) @@ -352,23 +355,23 @@ void RangeHoodManager::UpdateClusterState(intptr_t arg) RangeHoodManager::AttributeUpdateInfo * data = reinterpret_cast(arg); if (data->isSpeedCurrent) { - Attributes::SpeedCurrent::Set(data->endPoint, data->speedCurrent); + chip::app::Clusters::FanControl::Attributes::SpeedCurrent::Set(data->endPoint, data->speedCurrent); } else if (data->isPercentCurrent) { - Attributes::PercentCurrent::Set(data->endPoint, data->percentCurrent); + chip::app::Clusters::FanControl::Attributes::PercentCurrent::Set(data->endPoint, data->percentCurrent); } else if (data->isSpeedSetting) { - Attributes::SpeedSetting::Set(data->endPoint, data->speedSetting); + chip::app::Clusters::FanControl::Attributes::SpeedSetting::Set(data->endPoint, data->speedSetting); } else if (data->isFanMode) { - Attributes::FanMode::Set(data->endPoint, data->fanMode); + chip::app::Clusters::FanControl::Attributes::FanMode::Set(data->endPoint, data->fanMode); } else if (data->isPercentSetting) { - Attributes::PercentSetting::Set(data->endPoint, data->percentSetting); + chip::app::Clusters::FanControl::Attributes::PercentSetting::Set(data->endPoint, data->percentSetting); } chip::Platform::Delete(data); } @@ -377,12 +380,12 @@ void RangeHoodManager::HandleFanControlAttributeChange(AttributeId attributeId, { switch (attributeId) { - case Attributes::PercentSetting::Id: { + case chip::app::Clusters::FanControl::Attributes::PercentSetting::Id: { PercentSettingWriteCallback(*value); break; } - case Attributes::FanMode::Id: { + case chip::app::Clusters::FanControl::Attributes::FanMode::Id: { mFanMode = *reinterpret_cast(value); FanModeWriteCallback(mFanMode); break; @@ -533,7 +536,7 @@ DataModel::Nullable RangeHoodManager::GetSpeedSetting() { DataModel::Nullable speedSetting; - Status status = Attributes::SpeedSetting::Get(kExtractorHoodEndpoint1, speedSetting); + Status status = chip::app::Clusters::FanControl::Attributes::SpeedSetting::Get(kExtractorHoodEndpoint1, speedSetting); if (status != Status::Success) { ChipLogError(NotSpecified, "RangeHoodManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", @@ -547,7 +550,7 @@ DataModel::Nullable RangeHoodManager::GetPercentSetting() { DataModel::Nullable percentSetting; - Status status = Attributes::PercentSetting::Get(kExtractorHoodEndpoint1, percentSetting); + Status status = chip::app::Clusters::FanControl::Attributes::PercentSetting::Get(kExtractorHoodEndpoint1, percentSetting); if (status != Status::Success) { ChipLogError(NotSpecified, "RangeHoodManager::GetPercentSetting: failed to get PercentSetting attribute: %d", From cf49e8de5c4f7adc5dccb25a91e8cd2433c77284 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Tue, 28 Oct 2025 15:55:13 +0530 Subject: [PATCH 04/11] Added fanDelegate --- .../include/ExtractorHoodEndpoint.h | 18 ++++----- .../include/LightEndpoint.h | 2 +- .../src/ExtractorHoodEndpoint.cpp | 11 +++--- examples/rangehood-app/silabs/.gn copy | 29 ++++++++++++++ examples/rangehood-app/silabs/BUILD.gn | 1 + .../silabs/include/RangeHoodManager.h | 28 +++++++++++--- .../silabs/src/RangeHoodManager.cpp | 38 ++++++++++++++++--- 7 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 examples/rangehood-app/silabs/.gn copy diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h index 5aa89974887..8d755c893cc 100644 --- a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -34,7 +34,8 @@ using Protocols::InteractionModel::Status; namespace chip { namespace app { namespace Clusters { -namespace FanDelegate { +namespace ExtractorHood { + class FanDelegate : public FanControl::Delegate { public: @@ -51,29 +52,24 @@ class FanDelegate : public FanControl::Delegate */ Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; - FanDelegate(EndpointId aEndpoint) : mEndpoint(aEndpoint) {} + FanDelegate(EndpointId aEndpoint) + : FanControl::Delegate(aEndpoint), mEndpoint(aEndpoint) {} protected: EndpointId mEndpoint = 0; }; -} // namespace FanDelegate -namespace ExtractorHood { class ExtractorHoodEndpoint { public: - ExtractorHoodEndpoint(EndpointId endpointId) : mEndpointId(endpointId) {} + ExtractorHoodEndpoint(EndpointId endpointId) : mEndpointId(endpointId), mFanDelegate(mEndpointId) {} /** * @brief Initialize the ExtractorHood endpoint. */ CHIP_ERROR Init(); - /** - * @brief Get the FanDelegate instance for this endpoint. - */ - FanDelegate & GetFanDelegate() { return mFanDelegate; } - - /* Add ExtractorHoodEndpoint functions*/ + // Accessor for registering the fan control delegate + FanDelegate * GetFanDelegate() { return &mFanDelegate; } private: EndpointId mEndpointId = kInvalidEndpointId; diff --git a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h index ab4286b393f..6305f1d6d72 100644 --- a/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/LightEndpoint.h @@ -29,7 +29,7 @@ namespace Light { class LightEndpoint { public: - LightEndpoint() {} + LightEndpoint(EndpointId endpointId) : mEndpointId(endpointId) {} /** * @brief Initialize the Light endpoint. diff --git a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp index 59021be74bd..6bdb757051e 100644 --- a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp @@ -19,8 +19,9 @@ #include "RangeHoodManager.h" #include "ExtractorHoodEndpoint.h" -#include +#include +#include using namespace chip; using namespace chip::app::Clusters::ExtractorHood; @@ -32,8 +33,6 @@ CHIP_ERROR ExtractorHoodEndpoint::Init() Status FanDelegate::HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) { - ChipLogProgress(Zcl, "FanDelegate::HandleStep aDirection %d, aWrap %d, aLowestOff %d", to_underlying(aDirection), - aWrap, aLowestOff); - - RangeHoodManager::GetInstance().ProcessExtractorStepCommand(mEndpointId, aDirection, aWrap, aLowestOff); -} \ No newline at end of file + ChipLogProgress(Zcl, "FanDelegate::HandleStep direction=%d wrap=%d lowestOff=%d", to_underlying(aDirection), aWrap, aLowestOff); + return RangeHoodManager::GetInstance().ProcessExtractorStepCommand(mEndpoint, aDirection, aWrap, aLowestOff); +} diff --git a/examples/rangehood-app/silabs/.gn copy b/examples/rangehood-app/silabs/.gn copy new file mode 100644 index 00000000000..fe0e637d199 --- /dev/null +++ b/examples/rangehood-app/silabs/.gn copy @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + chip_openthread_ftd = true + + import("//openthread.gni") +} \ No newline at end of file diff --git a/examples/rangehood-app/silabs/BUILD.gn b/examples/rangehood-app/silabs/BUILD.gn index 8372348b610..618774d6c7f 100644 --- a/examples/rangehood-app/silabs/BUILD.gn +++ b/examples/rangehood-app/silabs/BUILD.gn @@ -76,6 +76,7 @@ if (wifi_soc) { "${examples_plat_dir}", "${chip_root}/src/lib", "${examples_common_plat_dir}", + "${example_rangehood_dir}/rangehood-app-common/include", ] defines = [] diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index 4fec8862bb8..2f028a56d92 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -36,6 +36,7 @@ #include #include +#include using namespace chip; using namespace chip::app; @@ -47,6 +48,24 @@ using Protocols::InteractionModel::Status; class RangeHoodManager { public: + RangeHoodManager() + : mState(kState_OffCompleted), + mActionInitiated_CB(nullptr), + mActionCompleted_CB(nullptr), + mAutoTurnOff(false), + mAutoTurnOffDuration(0), + mAutoTurnOffTimerArmed(false), + mOffEffectArmed(false), + mLightTimer(nullptr), + mFanMode(FanModeEnum::kOff), + mSpeedMax(0), + percentCurrent(0), + speedCurrent(0), + // initialize endpoint helpers with the required EndpointIds: + mExtractorHoodEndpoint1(kExtractorHoodEndpoint1), + mLightEndpoint2(kLightEndpoint2) + {} + enum Action_t { @@ -82,13 +101,12 @@ class RangeHoodManager void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value); - void PercentSettingWriteCallback(uint8_t aNewPercentSetting); + void PercentSettingWriteCallback(uint8_t aNewPercentSetting); void SpeedSettingWriteCallback(uint8_t aNewSpeedSetting); void FanModeWriteCallback(FanModeEnum aNewFanMode); void SetPercentSetting(Percent aNewPercentSetting); - // DataModel::Nullable GetSpeedSetting(); - // DataModel::Nullable GetPercentSetting(); + void UpdateFanMode(); static void UpdateClusterState(intptr_t arg); @@ -154,7 +172,7 @@ class RangeHoodManager uint8_t percentCurrent; uint8_t speedCurrent; - // Fan Mode Limits + //Fan Mode Limits static constexpr int kFanModeLowLowerBound = 1; static constexpr int kFanModeLowUpperBound = 3; static constexpr int kFanModeMediumLowerBound = 4; @@ -174,7 +192,7 @@ class RangeHoodManager // Define the endpoint ID for the RangeHood static constexpr chip::EndpointId kExtractorHoodEndpoint1 = 1; - static constexpr chip::EndpointId kLightEndpoint1 = 2; + static constexpr chip::EndpointId kLightEndpoint2 = 2; chip::app::Clusters::ExtractorHood::ExtractorHoodEndpoint mExtractorHoodEndpoint1; chip::app::Clusters::Light::LightEndpoint mLightEndpoint2; diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index ba4295c7213..48dfa25540e 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -25,6 +25,7 @@ #include "AppTask.h" #include +#include #include using namespace chip; @@ -62,9 +63,7 @@ CHIP_ERROR RangeHoodManager::Init() bool currentLedState; // read current on/off value on light endpoint. - chip::DeviceLayer::PlatformMgr().LockChipStack(); - OnOffServer::Instance().getOnOffValue(kLightEndpoint1, ¤tLedState); - + OnOffServer::Instance().getOnOffValue(kLightEndpoint2, ¤tLedState); chip::app::Clusters::FanControl::Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); @@ -76,13 +75,40 @@ CHIP_ERROR RangeHoodManager::Init() uint8_t speedSettingCB = speedSettingNullable.IsNull() ? 0 : speedSettingNullable.Value(); SpeedSettingWriteCallback(speedSettingCB); - FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, &mExtractorHoodEndpoint1.GetFanDelegate()); + // Register FanControl delegate (GetFanDelegate returns pointer) + FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, mExtractorHoodEndpoint1.GetFanDelegate()); DeviceLayer::PlatformMgr().UnlockChipStack(); return CHIP_NO_ERROR; } +void RangeHoodManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +bool RangeHoodManager::IsActionInProgress() +{ + return (mState == kState_OffInitiated || mState == kState_OnInitiated); +} + +bool RangeHoodManager::IsLightOn() +{ + return (mState == kState_OnCompleted); +} + +void RangeHoodManager::EnableAutoTurnOff(bool aOn) +{ + mAutoTurnOff = aOn; +} + +void RangeHoodManager::SetAutoTurnOffDuration(uint32_t aDurationInSecs) +{ + mAutoTurnOffDuration = aDurationInSecs; +} + bool RangeHoodManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue) { bool action_initiated = false; @@ -285,8 +311,8 @@ void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) } } - sRangeHoodMgr->mOffEffectArmed = true; - sRangeHoodMgr->StartTimer(offEffectDuration); + sRangeHoodMgr.mOffEffectArmed = true; + sRangeHoodMgr.StartTimer(offEffectDuration); } Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) From cec579c9b171fe0aa6495720869b1fa613e6f786 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Wed, 29 Oct 2025 14:28:21 +0530 Subject: [PATCH 05/11] Added button,LCD functionality to rangehood-app --- examples/rangehood-app/silabs/BUILD.gn | 1 + .../rangehood-app/silabs/include/AppTask.h | 4 + .../silabs/include/RangeHoodIcons.h | 41 +++++ .../silabs/include/RangeHoodManager.h | 8 +- .../silabs/include/RangeHoodUI.h | 38 +++++ examples/rangehood-app/silabs/src/AppTask.cpp | 72 ++++++-- .../silabs/src/RangeHoodManager.cpp | 62 +++---- .../rangehood-app/silabs/src/RangeHoodUI.cpp | 155 ++++++++++++++++++ 8 files changed, 322 insertions(+), 59 deletions(-) create mode 100644 examples/rangehood-app/silabs/include/RangeHoodIcons.h create mode 100644 examples/rangehood-app/silabs/include/RangeHoodUI.h create mode 100644 examples/rangehood-app/silabs/src/RangeHoodUI.cpp diff --git a/examples/rangehood-app/silabs/BUILD.gn b/examples/rangehood-app/silabs/BUILD.gn index 618774d6c7f..7d052f6e4f8 100644 --- a/examples/rangehood-app/silabs/BUILD.gn +++ b/examples/rangehood-app/silabs/BUILD.gn @@ -108,6 +108,7 @@ silabs_executable("rangehood_app") { "src/AppTask.cpp", "src/DataModelCallbacks.cpp", "src/RangeHoodManager.cpp", + "src/RangeHoodUI.cpp", ] deps = [ ":sdk" ] diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h index 5e8032ee827..9e74275f511 100644 --- a/examples/rangehood-app/silabs/include/AppTask.h +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -81,6 +81,8 @@ class AppTask : public BaseApplication static void ButtonEventHandler(uint8_t button, uint8_t btnAction); void PostLightActionRequest(int32_t aActor, RangeHoodManager::Action_t aAction); + void UpdateRangeHoodUI(); + private: static AppTask sAppTask; @@ -103,4 +105,6 @@ class AppTask : public BaseApplication * @param aEvent button event being processed */ static void ButtonHandler(AppEvent * aEvent); + // Work item executed on CHIP stack thread to toggle fan mode safely + static void SetFanOnOff(intptr_t context); }; diff --git a/examples/rangehood-app/silabs/include/RangeHoodIcons.h b/examples/rangehood-app/silabs/include/RangeHoodIcons.h new file mode 100644 index 00000000000..b1b0e35f1ca --- /dev/null +++ b/examples/rangehood-app/silabs/include/RangeHoodIcons.h @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#define SILABS_LOGO_WIDTH 47 +#define SILABS_LOGO_HEIGHT 18 +#define BLUETOOTH_ICON_SIZE 18 + +// Status Icon defines +#define STATUS_ICON_LINE 0 +#define SILABS_ICON_POSITION_X 0 +#define BLE_ICON_POSITION_X 72 +#define NETWORK_ICON_POSITION_X 90 +#define MATTER_ICON_POSITION_X 108 + +#define BLUETOOTH_ICON_SMALL \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x7F, 0xFE, 0xEF, 0xF1, 0x7F, 0x9F, 0xFF, 0x7B, 0xFF, 0x1F, 0xFE, 0xFF, 0xFC, 0xFF, \ + 0xF3, 0xFF, 0x87, 0xFF, 0xEF, 0xFD, 0xDF, 0xE7, 0xBF, 0xC7, 0xFF, 0x9F, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F + +#define SILABS_LOGO_SMALL \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, \ + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x9F, 0xFF, 0xE7, 0x3F, 0xE0, 0xF1, 0x83, \ + 0xFF, 0xF9, 0xEF, 0xFF, 0x3F, 0xE0, 0x3F, 0xFC, 0xFF, 0xFF, 0x7F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0x03, 0xFC, \ + 0xFF, 0xF7, 0x9F, 0xFF, 0x81, 0x07, 0x02, 0xF8, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0xFE, 0xFF, 0xFF, 0xF8, 0x03, 0xC0, 0xFF, \ + 0xFF, 0xFF, 0xFE, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0x3F diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index 2f028a56d92..56c4c32c3cd 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -112,9 +112,11 @@ class RangeHoodManager static void UpdateClusterState(intptr_t arg); FanModeEnum GetFanMode(); - void UpdateFanControlLED(); - void UpdateFanControlLCD(); - EndpointId GetEndPoint(); + void UpdateRangeHoodLCD(); + + // Explicit getters for individual endpoints + EndpointId GetExtractorEndpoint() { return kExtractorHoodEndpoint1; } + EndpointId GetLightEndpoint() { return kLightEndpoint2; } struct AttributeUpdateInfo { diff --git a/examples/rangehood-app/silabs/include/RangeHoodUI.h b/examples/rangehood-app/silabs/include/RangeHoodUI.h new file mode 100644 index 00000000000..a456244ade7 --- /dev/null +++ b/examples/rangehood-app/silabs/include/RangeHoodUI.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "demo-ui-bitmaps.h" +#include "dmd.h" +#include "glib.h" +#include "lcd.h" +#include + +class RangeHoodUI +{ + +public: + static void DrawUI(GLIB_Context_t * glibContext); + +private: + static void DrawHeader(GLIB_Context_t * glibContext); + static void DrawRangehoodStatus(GLIB_Context_t * glibContext); + static void DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, + uint32_t size); +}; diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp index 13b0a6bca57..48753e71bba 100644 --- a/examples/rangehood-app/silabs/src/AppTask.cpp +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -24,6 +24,7 @@ #include "LEDWidget.h" #ifdef DISPLAY_ENABLED +#include "RangeHoodUI.h" #include "lcd.h" #ifdef QR_CODE_ENABLED #include "qrcodegen.h" @@ -37,6 +38,7 @@ #include #include #include +#include #include @@ -49,6 +51,8 @@ #include #include +#include + #define LIGHT_LED 1 @@ -75,7 +79,12 @@ CHIP_ERROR AppTask::AppInit() CHIP_ERROR err = CHIP_NO_ERROR; chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler); - // Initialization of Oven Manager and endpoints of oven. +#ifdef DISPLAY_ENABLED + GetLCD().Init((uint8_t *) "Rangehood-App"); + GetLCD().SetCustomUI(RangeHoodUI::DrawUI); +#endif + + // Initialization of RangeHoodManager and endpoints of range hood. RangeHoodManager::GetInstance().Init(); RangeHoodManager::GetInstance().SetCallbacks(ActionInitiated, ActionCompleted); @@ -138,8 +147,18 @@ void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) AppEvent button_event = {}; button_event.Type = AppEvent::kEventType_Button; button_event.ButtonEvent.Action = btnAction; - button_event.Handler = BaseApplication::ButtonHandler; - AppTask::GetAppTask().PostEvent(&button_event); + // Only invoke our RangeHood ButtonHandler for BTN1 (APP_ACTION_BUTTON) presses. + if (button == APP_ACTION_BUTTON && btnAction == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) + { + button_event.Handler = ButtonHandler; + AppTask::GetAppTask().PostEvent(&button_event); + } + else if (button == APP_FUNCTION_BUTTON) + { + // Defer other button events to generic base handler (factory reset, etc.) + button_event.Handler = BaseApplication::ButtonHandler; + AppTask::GetAppTask().PostEvent(&button_event); + } } void AppTask::ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * aValue) @@ -147,11 +166,9 @@ void AppTask::ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor bool lightOn = aAction == RangeHoodManager::ON_ACTION; SILABS_LOG("Turning light %s", (lightOn) ? "On" : "Off"); - sLightLED.Set(lightOn); + sLightLED.Set(lightOn); -#ifdef DISPLAY_ENABLED - sAppTask.GetLCD().WriteDemoUI(lightOn); -#endif + // Defer LCD refresh until ActionCompleted so RangeHoodMgr().IsLightOn() reflects final state. if (aActor == AppEvent::kEventType_Button) { @@ -165,12 +182,19 @@ void AppTask::ActionCompleted(RangeHoodManager::Action_t aAction) if (aAction == RangeHoodManager::ON_ACTION) { SILABS_LOG("Light ON"); + sLightLED.Set(true); } else if (aAction == RangeHoodManager::OFF_ACTION) { SILABS_LOG("Light OFF"); + sLightLED.Set(false); } +#if DISPLAY_ENABLED + // Refresh LCD now that RangeHoodMgr().IsLightOn() is authoritative. + AppTask::GetAppTask().UpdateRangeHoodUI(); +#endif + if (sAppTask.mSyncClusterToButtonAction) { // TODO: Schedule work to Update Light Endpoints (turn on/off) @@ -178,12 +202,32 @@ void AppTask::ActionCompleted(RangeHoodManager::Action_t aAction) } } -void AppTask::PostLightActionRequest(int32_t aActor, RangeHoodManager::Action_t aAction) +void AppTask::SetFanOnOff(intptr_t context) { - AppEvent event; - event.Type = AppEvent::kEventType_RangeHood; - event.RangeHoodEvent.Actor = aActor; - event.RangeHoodEvent.Action = aAction; - // event.Handler = LightActionEventHandler; - PostEvent(&event); + EndpointId endpoint = RangeHoodMgr().GetExtractorEndpoint(); + FanModeEnum currentFanMode; + if (FanControl::Attributes::FanMode::Get(endpoint, ¤tFanMode) == Protocols::InteractionModel::Status::Success) + { + FanModeEnum target = (currentFanMode == FanModeEnum::kOff) ? FanModeEnum::kHigh : FanModeEnum::kOff; + FanControl::Attributes::FanMode::Set(endpoint, target); + } +} + +void AppTask::ButtonHandler(AppEvent * aEvent) +{ + // Distinguish between function and action buttons + if (aEvent->ButtonEvent.Action == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) + { + // Fan toggle using same button for now (could be separated if button id available) + // Schedule fan mode toggle on CHIP stack thread to avoid direct access causing locking errors. + chip::DeviceLayer::PlatformMgr().ScheduleWork(SetFanOnOff, 0); + } +} + +void AppTask::UpdateRangeHoodUI() +{ + // Update the LCD with the Stored value. Show QR Code if not provisioned +#ifdef DISPLAY_ENABLED + GetLCD().WriteDemoUI(false); +#endif // DISPLAY_ENABLED } diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index 48dfa25540e..dcaa7f6ab0d 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -28,6 +28,10 @@ #include #include +#if DISPLAY_ENABLED +#include "RangeHoodUI.h" +#endif + using namespace chip; using namespace chip::app; using namespace ::chip::app::Clusters; @@ -71,15 +75,13 @@ CHIP_ERROR RangeHoodManager::Init() uint8_t percentSettingCB = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value(); PercentSettingWriteCallback(percentSettingCB); - DataModel::Nullable speedSettingNullable = GetSpeedSetting(); - uint8_t speedSettingCB = speedSettingNullable.IsNull() ? 0 : speedSettingNullable.Value(); - SpeedSettingWriteCallback(speedSettingCB); - // Register FanControl delegate (GetFanDelegate returns pointer) FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, mExtractorHoodEndpoint1.GetFanDelegate()); DeviceLayer::PlatformMgr().UnlockChipStack(); + mState = currentLedState ? kState_OnCompleted : kState_OffCompleted; + return CHIP_NO_ERROR; } @@ -414,6 +416,9 @@ void RangeHoodManager::HandleFanControlAttributeChange(AttributeId attributeId, case chip::app::Clusters::FanControl::Attributes::FanMode::Id: { mFanMode = *reinterpret_cast(value); FanModeWriteCallback(mFanMode); +#if DISPLAY_ENABLED + UpdateRangeHoodLCD(); +#endif break; } @@ -441,43 +446,6 @@ void RangeHoodManager::PercentSettingWriteCallback(uint8_t aNewPercentSetting) } } -void RangeHoodManager::SpeedSettingWriteCallback(uint8_t aNewSpeedSetting) -{ - VerifyOrReturn(aNewSpeedSetting != speedCurrent); - VerifyOrReturn(mFanMode != FanModeEnum::kAuto); - ChipLogDetail(NotSpecified, "RangeHoodManager::SpeedSettingWriteCallback: %d", aNewSpeedSetting); - speedCurrent = aNewSpeedSetting; - - AttributeUpdateInfo * data = chip::Platform::New(); - data->endPoint = kExtractorHoodEndpoint1; - data->speedCurrent = speedCurrent; - data->isSpeedCurrent = true; - - if (chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(data)) != CHIP_NO_ERROR) - { - ChipLogError(NotSpecified, "RangeHoodManager::SpeedSettingWriteCallback: failed to set SpeedCurrent attribute"); - } - - // Update the fan mode as per the current speed. - if (speedCurrent == 0) - { - mFanMode = FanModeEnum::kOff; - } - else if (speedCurrent <= kFanModeLowUpperBound) - { - mFanMode = FanModeEnum::kLow; - } - else if (speedCurrent <= kFanModeMediumUpperBound) - { - mFanMode = FanModeEnum::kMedium; - } - else if (speedCurrent <= kFanModeHighUpperBound) - { - mFanMode = FanModeEnum::kHigh; - } - UpdateFanMode(); -} - void RangeHoodManager::UpdateFanMode() { AttributeUpdateInfo * data = chip::Platform::New(); @@ -558,6 +526,11 @@ void RangeHoodManager::SetPercentSetting(Percent aNewPercentSetting) } } +FanModeEnum RangeHoodManager::GetFanMode() +{ + return mFanMode; +} + DataModel::Nullable RangeHoodManager::GetSpeedSetting() { DataModel::Nullable speedSetting; @@ -584,4 +557,9 @@ DataModel::Nullable RangeHoodManager::GetPercentSetting() } return percentSetting; -} \ No newline at end of file +} + +void RangeHoodManager::UpdateRangeHoodLCD() +{ + AppTask::GetAppTask().UpdateRangeHoodUI(); +} diff --git a/examples/rangehood-app/silabs/src/RangeHoodUI.cpp b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp new file mode 100644 index 00000000000..7984e1fc008 --- /dev/null +++ b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp @@ -0,0 +1,155 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "AppTask.h" +#include "RangeHoodManager.h" +#include "RangeHoodUI.h" +#include "demo-ui-bitmaps.h" +#include "dmd.h" +#include "glib.h" +#include "lcd.h" + +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::FanControl; + +namespace { +// Bitmap +const uint8_t silabsLogo[] = { SILABS_LOGO_SMALL }; +const uint8_t matterLogoBitmap[] = { MATTER_LOGO_BITMAP }; + +const uint8_t wifiLogo[] = { WIFI_BITMAP }; +const uint8_t threadLogo[] = { THREAD_BITMAP }; +const uint8_t bleLogo[] = { BLUETOOTH_ICON_SMALL }; + +#ifdef SL_WIFI +constexpr bool UI_WIFI = true; +#else +constexpr bool UI_WIFI = false; +#endif +} // namespace + +void RangeHoodUI::DrawUI(GLIB_Context_t * glibContext) +{ + if (glibContext == nullptr) + { + ChipLogError(AppServer, "Context is null"); + return; + } + + GLIB_clear(glibContext); + DrawHeader(glibContext); + DrawRangehoodStatus(glibContext); + +#if SL_LCDCTRL_MUX + sl_wfx_host_pre_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX + DMD_updateDisplay(); +#if SL_LCDCTRL_MUX + sl_wfx_host_post_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX +} + +void RangeHoodUI::DrawHeader(GLIB_Context_t * glibContext) +{ + // Draw Silabs Corner icon + GLIB_drawBitmap(glibContext, SILABS_ICON_POSITION_X, STATUS_ICON_LINE, SILABS_LOGO_WIDTH, SILABS_LOGO_HEIGHT, silabsLogo); + // Draw BLE Icon + GLIB_drawBitmap(glibContext, BLE_ICON_POSITION_X, STATUS_ICON_LINE, BLUETOOTH_ICON_SIZE, BLUETOOTH_ICON_SIZE, bleLogo); + // Draw WiFi/OpenThread Icon + GLIB_drawBitmap(glibContext, NETWORK_ICON_POSITION_X, STATUS_ICON_LINE, (UI_WIFI) ? WIFI_BITMAP_WIDTH : THREAD_BITMAP_WIDTH, + WIFI_BITMAP_HEIGHT, (UI_WIFI) ? wifiLogo : threadLogo); + // Draw Matter Icon + GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap); + + // Draw application name on a dedicated line below icons. + GLIB_drawStringOnLine(glibContext, "RangeHood-App", 3, GLIB_ALIGN_CENTER, 0, 0, true); +#if SL_LCDCTRL_MUX + sl_wfx_host_pre_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX + DMD_updateDisplay(); +#if SL_LCDCTRL_MUX + sl_wfx_host_post_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX +} + +/** + * @brief Draw a 2 digit Air Quality of screen. Because of this Celsius is used by default + * @param GLIB_Context_t * pointer to the context for the GLIB library + * @param int8_t current Air Quality + */ +void RangeHoodUI::DrawRangehoodStatus(GLIB_Context_t * glibContext) +{ + SILABS_LOG("Updating Rangehood Status on LCD"); + FanModeEnum mode = RangeHoodMgr().GetFanMode(); + bool lightOn = RangeHoodMgr().IsLightOn(); + // Print fan mode + if (mode == FanModeEnum::kOff) + { + GLIB_drawStringOnLine(glibContext, "FAN : OFF", 5, GLIB_ALIGN_LEFT, 0, 0, true); + } + else if (mode == FanModeEnum::kUnknownEnumValue) + { + GLIB_drawStringOnLine(glibContext, "FAN : UNKNOWN", 5, GLIB_ALIGN_LEFT, 0, 0, true); + } + else + { + GLIB_drawStringOnLine(glibContext, "FAN : ON", 5, GLIB_ALIGN_LEFT, 0, 0, true); + } + + // Draw Light status below speed information (choose line 8 for consistency) + GLIB_drawStringOnLine(glibContext, lightOn ? "LIGHT : ON" : "LIGHT : OFF", 7, GLIB_ALIGN_LEFT, 0, 0, true); + +#if SL_LCDCTRL_MUX + sl_wfx_host_pre_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX + DMD_updateDisplay(); +#if SL_LCDCTRL_MUX + sl_wfx_host_post_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX +} + +void RangeHoodUI::DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, + uint32_t size) +{ + uint8_t x = initial_x, y = initial_y; + for (uint16_t i = 0; i < size; i++) + { + for (uint8_t mask = 0; mask < 8; mask++) + { + if (!(data[i] & (0x01 << mask))) + { + GLIB_drawPixel(glibContext, x, y); + } + // Check line changes + if (((x - initial_x) % width) == 0 && x != initial_x) + { + x = initial_x; + y++; + // Font is 8 bit align with paddings bits; + mask = 8; + } + else + { + x++; + } + } + } +} From 497571f449f40c99866c898e731111b9cebdd50e Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 29 Oct 2025 08:59:06 +0000 Subject: [PATCH 06/11] Restyled by whitespace --- .../rangehood-app-common/src/ExtractorHoodEndpoint.cpp | 2 +- .../rangehood-app-common/src/LightEndpoint.cpp | 2 +- examples/rangehood-app/silabs/include/AppTask.h | 2 +- examples/rangehood-app/silabs/include/RangeHoodManager.h | 6 +++--- examples/rangehood-app/silabs/src/DataModelCallbacks.cpp | 8 ++++---- examples/rangehood-app/silabs/src/RangeHoodManager.cpp | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp index 6bdb757051e..2ed4b51f9a3 100644 --- a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp @@ -19,7 +19,7 @@ #include "RangeHoodManager.h" #include "ExtractorHoodEndpoint.h" -#include +#include #include diff --git a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp index 4cc6cb5a381..75823959953 100644 --- a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp @@ -47,4 +47,4 @@ void LightEndpoint::SetOnOffState(bool state) { ChipLogError(AppServer, "ERR: updating on/off %x", to_underlying(status)); } -} \ No newline at end of file +} diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h index 9e74275f511..b186a377e7b 100644 --- a/examples/rangehood-app/silabs/include/AppTask.h +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -88,7 +88,7 @@ class AppTask : public BaseApplication static void ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * value); static void ActionCompleted(RangeHoodManager::Action_t aAction); - + static void LightActionEventHandler(AppEvent * aEvent); /** * @brief Override of BaseApplication::AppInit() virtual method, called by BaseApplication::Init() diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index 56c4c32c3cd..07d1b015f9a 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -65,7 +65,7 @@ class RangeHoodManager mExtractorHoodEndpoint1(kExtractorHoodEndpoint1), mLightEndpoint2(kLightEndpoint2) {} - + enum Action_t { @@ -95,7 +95,7 @@ class RangeHoodManager static void OnTriggerOffWithEffect(OnOffEffect * effect); /** - * @brief Central handler for delegate requests, Handle the step command from the Fan Control Cluster + * @brief Central handler for delegate requests, Handle the step command from the Fan Control Cluster */ Status ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff); @@ -189,7 +189,7 @@ class RangeHoodManager DataModel::Nullable GetSpeedSetting(); static RangeHoodManager sRangeHoodMgr; - + // FanControlDelegate object // Define the endpoint ID for the RangeHood diff --git a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp index 85d6d51ab5e..97f56569fa2 100644 --- a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp +++ b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp @@ -41,7 +41,7 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; EndpointId endpointId = attributePath.mEndpointId; - + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI " on endpoint %u", ChipLogValueMEI(clusterId), endpointId); switch (clusterId) @@ -50,18 +50,18 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & // Fan control should only be on FAN ENDPOINT RangeHoodMgr().HandleFanControlAttributeChange(attributeId, type, size, value); break; - + case OnOff::Id: // Light on/off control should only be on LIGHT_ENDPOINT RangeHoodMgr().InitiateAction(AppEvent::kEventType_RangeHood, *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, value); break; - + case Identify::Id: ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u on endpoint %u", ChipLogValueMEI(attributeId), type, *value, size, endpointId); break; - + default: ChipLogProgress(Zcl, "Unhandled cluster " ChipLogFormatMEI " on endpoint %u", ChipLogValueMEI(clusterId), endpointId); break; diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index dcaa7f6ab0d..582a567ab70 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -66,7 +66,7 @@ CHIP_ERROR RangeHoodManager::Init() bool currentLedState; - // read current on/off value on light endpoint. + // read current on/off value on light endpoint. OnOffServer::Instance().getOnOffValue(kLightEndpoint2, ¤tLedState); chip::app::Clusters::FanControl::Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); @@ -79,9 +79,9 @@ CHIP_ERROR RangeHoodManager::Init() FanControl::SetDefaultDelegate(kExtractorHoodEndpoint1, mExtractorHoodEndpoint1.GetFanDelegate()); DeviceLayer::PlatformMgr().UnlockChipStack(); - + mState = currentLedState ? kState_OnCompleted : kState_OffCompleted; - + return CHIP_NO_ERROR; } @@ -316,7 +316,7 @@ void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) sRangeHoodMgr.mOffEffectArmed = true; sRangeHoodMgr.StartTimer(offEffectDuration); } - + Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) { ChipLogProgress(AppServer, "RangeHoodManager::ProcessExtractorStepCommand ep=%u aDirection %d, aWrap %d, aLowestOff %d", endpointId, to_underlying(aDirection), From bf8f9f942b24b53787a1ddca9c88dd4ca73fb9ae Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 29 Oct 2025 08:59:11 +0000 Subject: [PATCH 07/11] Restyled by clang-format --- .../include/ExtractorHoodEndpoint.h | 3 +- .../src/ExtractorHoodEndpoint.cpp | 2 +- .../silabs/include/RangeHoodManager.h | 39 +++++++------------ examples/rangehood-app/silabs/src/AppTask.cpp | 13 ++++--- .../silabs/src/DataModelCallbacks.cpp | 4 +- .../silabs/src/RangeHoodManager.cpp | 19 ++++----- .../rangehood-app/silabs/src/RangeHoodUI.cpp | 4 +- 7 files changed, 37 insertions(+), 47 deletions(-) diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h index 8d755c893cc..ce7e32ab50c 100644 --- a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -52,8 +52,7 @@ class FanDelegate : public FanControl::Delegate */ Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; - FanDelegate(EndpointId aEndpoint) - : FanControl::Delegate(aEndpoint), mEndpoint(aEndpoint) {} + FanDelegate(EndpointId aEndpoint) : FanControl::Delegate(aEndpoint), mEndpoint(aEndpoint) {} protected: EndpointId mEndpoint = 0; diff --git a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp index 2ed4b51f9a3..b76a0e6c3b8 100644 --- a/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/ExtractorHoodEndpoint.cpp @@ -16,8 +16,8 @@ * limitations under the License. */ -#include "RangeHoodManager.h" #include "ExtractorHoodEndpoint.h" +#include "RangeHoodManager.h" #include diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index 07d1b015f9a..e7c8946db7c 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -32,41 +32,30 @@ #include "AppEvent.h" #include -#include #include +#include -#include #include +#include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters::FanControl; -using chip::Percent; using chip::EndpointId; +using chip::Percent; using Protocols::InteractionModel::Status; class RangeHoodManager { public: - RangeHoodManager() - : mState(kState_OffCompleted), - mActionInitiated_CB(nullptr), - mActionCompleted_CB(nullptr), - mAutoTurnOff(false), - mAutoTurnOffDuration(0), - mAutoTurnOffTimerArmed(false), - mOffEffectArmed(false), - mLightTimer(nullptr), - mFanMode(FanModeEnum::kOff), - mSpeedMax(0), - percentCurrent(0), - speedCurrent(0), - // initialize endpoint helpers with the required EndpointIds: - mExtractorHoodEndpoint1(kExtractorHoodEndpoint1), - mLightEndpoint2(kLightEndpoint2) + RangeHoodManager() : + mState(kState_OffCompleted), mActionInitiated_CB(nullptr), mActionCompleted_CB(nullptr), mAutoTurnOff(false), + mAutoTurnOffDuration(0), mAutoTurnOffTimerArmed(false), mOffEffectArmed(false), mLightTimer(nullptr), + mFanMode(FanModeEnum::kOff), mSpeedMax(0), percentCurrent(0), speedCurrent(0), + // initialize endpoint helpers with the required EndpointIds: + mExtractorHoodEndpoint1(kExtractorHoodEndpoint1), mLightEndpoint2(kLightEndpoint2) {} - enum Action_t { ON_ACTION = 0, @@ -101,7 +90,7 @@ class RangeHoodManager void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value); - void PercentSettingWriteCallback(uint8_t aNewPercentSetting); + void PercentSettingWriteCallback(uint8_t aNewPercentSetting); void SpeedSettingWriteCallback(uint8_t aNewSpeedSetting); void FanModeWriteCallback(FanModeEnum aNewFanMode); @@ -118,7 +107,7 @@ class RangeHoodManager EndpointId GetExtractorEndpoint() { return kExtractorHoodEndpoint1; } EndpointId GetLightEndpoint() { return kLightEndpoint2; } - struct AttributeUpdateInfo + struct AttributeUpdateInfo { FanModeEnum fanMode; uint8_t speedCurrent; @@ -174,7 +163,7 @@ class RangeHoodManager uint8_t percentCurrent; uint8_t speedCurrent; - //Fan Mode Limits + // Fan Mode Limits static constexpr int kFanModeLowLowerBound = 1; static constexpr int kFanModeLowUpperBound = 3; static constexpr int kFanModeMediumLowerBound = 4; @@ -193,8 +182,8 @@ class RangeHoodManager // FanControlDelegate object // Define the endpoint ID for the RangeHood - static constexpr chip::EndpointId kExtractorHoodEndpoint1 = 1; - static constexpr chip::EndpointId kLightEndpoint2 = 2; + static constexpr chip::EndpointId kExtractorHoodEndpoint1 = 1; + static constexpr chip::EndpointId kLightEndpoint2 = 2; chip::app::Clusters::ExtractorHood::ExtractorHoodEndpoint mExtractorHoodEndpoint1; chip::app::Clusters::Light::LightEndpoint mLightEndpoint2; diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp index 48753e71bba..d9f41c73ffb 100644 --- a/examples/rangehood-app/silabs/src/AppTask.cpp +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -33,12 +33,12 @@ #include "RangeHoodManager.h" #include +#include #include #include #include #include #include -#include #include @@ -53,7 +53,6 @@ #include #include - #define LIGHT_LED 1 #define APP_FUNCTION_BUTTON 0 @@ -84,7 +83,7 @@ CHIP_ERROR AppTask::AppInit() GetLCD().SetCustomUI(RangeHoodUI::DrawUI); #endif - // Initialization of RangeHoodManager and endpoints of range hood. + // Initialization of RangeHoodManager and endpoints of range hood. RangeHoodManager::GetInstance().Init(); RangeHoodManager::GetInstance().SetCallbacks(ActionInitiated, ActionCompleted); @@ -148,7 +147,8 @@ void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) button_event.Type = AppEvent::kEventType_Button; button_event.ButtonEvent.Action = btnAction; // Only invoke our RangeHood ButtonHandler for BTN1 (APP_ACTION_BUTTON) presses. - if (button == APP_ACTION_BUTTON && btnAction == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) + if (button == APP_ACTION_BUTTON && + btnAction == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) { button_event.Handler = ButtonHandler; AppTask::GetAppTask().PostEvent(&button_event); @@ -166,7 +166,7 @@ void AppTask::ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor bool lightOn = aAction == RangeHoodManager::ON_ACTION; SILABS_LOG("Turning light %s", (lightOn) ? "On" : "Off"); - sLightLED.Set(lightOn); + sLightLED.Set(lightOn); // Defer LCD refresh until ActionCompleted so RangeHoodMgr().IsLightOn() reflects final state. @@ -216,7 +216,8 @@ void AppTask::SetFanOnOff(intptr_t context) void AppTask::ButtonHandler(AppEvent * aEvent) { // Distinguish between function and action buttons - if (aEvent->ButtonEvent.Action == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) + if (aEvent->ButtonEvent.Action == + static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) { // Fan toggle using same button for now (could be separated if button id available) // Schedule fan mode toggle on CHIP stack thread to avoid direct access causing locking errors. diff --git a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp index 97f56569fa2..495541ea15e 100644 --- a/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp +++ b/examples/rangehood-app/silabs/src/DataModelCallbacks.cpp @@ -53,8 +53,8 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & case OnOff::Id: // Light on/off control should only be on LIGHT_ENDPOINT - RangeHoodMgr().InitiateAction(AppEvent::kEventType_RangeHood, *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, - value); + RangeHoodMgr().InitiateAction(AppEvent::kEventType_RangeHood, + *value ? RangeHoodManager::ON_ACTION : RangeHoodManager::OFF_ACTION, value); break; case Identify::Id: diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index 582a567ab70..7f0530e0429 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -51,7 +51,7 @@ CHIP_ERROR RangeHoodManager::Init() VerifyOrReturnError(mLightEndpoint2.Init() == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); - // Create cmsis os sw timer for light timer. + // Create cmsis os sw timer for light timer. mLightTimer = osTimerNew(TimerEventHandler, // timer callback handler osTimerOnce, // no timer reload (one-shot timer) (void *) this, // pass the app task obj context @@ -80,7 +80,7 @@ CHIP_ERROR RangeHoodManager::Init() DeviceLayer::PlatformMgr().UnlockChipStack(); - mState = currentLedState ? kState_OnCompleted : kState_OffCompleted; + mState = currentLedState ? kState_OnCompleted : kState_OffCompleted; return CHIP_NO_ERROR; } @@ -205,8 +205,8 @@ void RangeHoodManager::TimerEventHandler(void * timerCbArg) void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) { RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); - int32_t actor = AppEvent::kEventType_Timer; - uint8_t value = aEvent->RangeHoodEvent.Value; + int32_t actor = AppEvent::kEventType_Timer; + uint8_t value = aEvent->RangeHoodEvent.Value; // Make sure auto turn off timer is still armed. if (!light->mAutoTurnOffTimerArmed) @@ -224,8 +224,8 @@ void RangeHoodManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) void RangeHoodManager::OffEffectTimerEventHandler(AppEvent * aEvent) { RangeHoodManager * light = static_cast(aEvent->TimerEvent.Context); - int32_t actor = AppEvent::kEventType_Timer; - uint8_t value = aEvent->RangeHoodEvent.Value; + int32_t actor = AppEvent::kEventType_Timer; + uint8_t value = aEvent->RangeHoodEvent.Value; // Make sure auto turn off timer is still armed. if (!light->mOffEffectArmed) @@ -317,10 +317,11 @@ void RangeHoodManager::OnTriggerOffWithEffect(OnOffEffect * effect) sRangeHoodMgr.StartTimer(offEffectDuration); } -Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) +Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId, StepDirectionEnum aDirection, bool aWrap, + bool aLowestOff) { - ChipLogProgress(AppServer, "RangeHoodManager::ProcessExtractorStepCommand ep=%u aDirection %d, aWrap %d, aLowestOff %d", endpointId, to_underlying(aDirection), - aWrap, aLowestOff); + ChipLogProgress(AppServer, "RangeHoodManager::ProcessExtractorStepCommand ep=%u aDirection %d, aWrap %d, aLowestOff %d", + endpointId, to_underlying(aDirection), aWrap, aLowestOff); VerifyOrReturnError(aDirection != StepDirectionEnum::kUnknownEnumValue, Status::InvalidCommand); diff --git a/examples/rangehood-app/silabs/src/RangeHoodUI.cpp b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp index 7984e1fc008..82df227734a 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodUI.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp @@ -80,7 +80,7 @@ void RangeHoodUI::DrawHeader(GLIB_Context_t * glibContext) GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap); // Draw application name on a dedicated line below icons. - GLIB_drawStringOnLine(glibContext, "RangeHood-App", 3, GLIB_ALIGN_CENTER, 0, 0, true); + GLIB_drawStringOnLine(glibContext, "RangeHood-App", 3, GLIB_ALIGN_CENTER, 0, 0, true); #if SL_LCDCTRL_MUX sl_wfx_host_pre_lcd_spi_transfer(); #endif // SL_LCDCTRL_MUX @@ -127,7 +127,7 @@ void RangeHoodUI::DrawRangehoodStatus(GLIB_Context_t * glibContext) } void RangeHoodUI::DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, - uint32_t size) + uint32_t size) { uint8_t x = initial_x, y = initial_y; for (uint16_t i = 0; i < size; i++) From 0cfc7bd87c9a663469fb23ebf1aed43775e1b073 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 29 Oct 2025 08:59:14 +0000 Subject: [PATCH 08/11] Restyled by gn --- examples/rangehood-app/silabs/.gn | 4 ++-- examples/rangehood-app/silabs/BUILD.gn | 7 ++++--- examples/rangehood-app/silabs/build_for_wifi_gnfile.gn | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/rangehood-app/silabs/.gn b/examples/rangehood-app/silabs/.gn index fe0e637d199..541506fddce 100644 --- a/examples/rangehood-app/silabs/.gn +++ b/examples/rangehood-app/silabs/.gn @@ -24,6 +24,6 @@ default_args = { target_cpu = "arm" target_os = "freertos" chip_openthread_ftd = true - + import("//openthread.gni") -} \ No newline at end of file +} diff --git a/examples/rangehood-app/silabs/BUILD.gn b/examples/rangehood-app/silabs/BUILD.gn index 7d052f6e4f8..21d5c99b27b 100644 --- a/examples/rangehood-app/silabs/BUILD.gn +++ b/examples/rangehood-app/silabs/BUILD.gn @@ -36,8 +36,9 @@ examples_common_plat_dir = "${chip_root}/examples/platform/silabs" example_rangehood_dir = "${chip_root}/examples/rangehood-app" #if (wifi_soc) { - import("${chip_root}/third_party/silabs/SiWx917_sdk.gni") - examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917" +import("${chip_root}/third_party/silabs/SiWx917_sdk.gni") +examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917" + #} import("${examples_common_plat_dir}/args.gni") @@ -194,4 +195,4 @@ group("silabs") { group("default") { deps = [ ":silabs" ] -} \ No newline at end of file +} diff --git a/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn b/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn index b13f5432972..3b74d4e5326 100644 --- a/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn +++ b/examples/rangehood-app/silabs/build_for_wifi_gnfile.gn @@ -26,4 +26,4 @@ default_args = { chip_enable_wifi = true chip_device_platform = "SiWx917" import("//build_for_wifi_args.gni") -} \ No newline at end of file +} From be0ec91799eb43763835666628aca016000038d7 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Fri, 31 Oct 2025 15:28:42 +0530 Subject: [PATCH 09/11] Removed speed related code --- .../rangehood-app-common/rangehood-app.matter | 4 +- .../rangehood-app-common/rangehood-app.zap | 110 ++++++++++-------- .../silabs/build_for_wifi_args.gni | 2 +- .../rangehood-app/silabs/include/AppConfig.h | 2 +- .../rangehood-app/silabs/include/AppTask.h | 10 +- .../silabs/include/RangeHoodManager.h | 30 ++--- .../silabs/include/RangeHoodUI.h | 2 - examples/rangehood-app/silabs/src/AppTask.cpp | 13 ++- .../silabs/src/RangeHoodManager.cpp | 78 ++++--------- .../rangehood-app/silabs/src/RangeHoodUI.cpp | 31 +---- 10 files changed, 113 insertions(+), 169 deletions(-) diff --git a/examples/rangehood-app/rangehood-app-common/rangehood-app.matter b/examples/rangehood-app/rangehood-app-common/rangehood-app.matter index d6a791cf815..27a660e92e4 100644 --- a/examples/rangehood-app/rangehood-app-common/rangehood-app.matter +++ b/examples/rangehood-app/rangehood-app-common/rangehood-app.matter @@ -2346,8 +2346,10 @@ endpoint 1 { callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 16; ram attribute clusterRevision default = 5; + + handle command Step; } } endpoint 2 { diff --git a/examples/rangehood-app/rangehood-app-common/rangehood-app.zap b/examples/rangehood-app/rangehood-app-common/rangehood-app.zap index 488903c2837..2e2fc3e39d0 100644 --- a/examples/rangehood-app/rangehood-app-common/rangehood-app.zap +++ b/examples/rangehood-app/rangehood-app-common/rangehood-app.zap @@ -2734,7 +2734,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2750,7 +2750,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2766,7 +2766,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2782,7 +2782,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2798,7 +2798,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2814,7 +2814,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2830,7 +2830,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2846,7 +2846,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2862,7 +2862,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2877,6 +2877,16 @@ "define": "FAN_CONTROL_CLUSTER", "side": "server", "enabled": 1, + "commands": [ + { + "name": "Step", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], "attributes": [ { "name": "FanMode", @@ -2952,7 +2962,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2968,7 +2978,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2984,7 +2994,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3000,7 +3010,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "16", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3091,8 +3101,8 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", - "reportable": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3107,8 +3117,8 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", - "reportable": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3123,7 +3133,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3139,7 +3149,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3155,7 +3165,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3171,7 +3181,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3187,7 +3197,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3296,7 +3306,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "0x00", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3311,7 +3321,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3327,7 +3337,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3343,7 +3353,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3452,7 +3462,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3468,7 +3478,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3484,7 +3494,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3500,7 +3510,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3516,7 +3526,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3531,7 +3541,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3547,7 +3557,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3563,7 +3573,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3621,7 +3631,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3637,8 +3647,8 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", - "reportable": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3653,8 +3663,8 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", - "reportable": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3669,8 +3679,8 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", - "reportable": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -3685,7 +3695,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3701,7 +3711,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3717,7 +3727,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3733,7 +3743,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3749,7 +3759,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3914,7 +3924,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3930,7 +3940,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3946,7 +3956,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3962,7 +3972,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/rangehood-app/silabs/build_for_wifi_args.gni b/examples/rangehood-app/silabs/build_for_wifi_args.gni index 50ffa4e778a..9e7ff54b8ab 100644 --- a/examples/rangehood-app/silabs/build_for_wifi_args.gni +++ b/examples/rangehood-app/silabs/build_for_wifi_args.gni @@ -18,5 +18,5 @@ chip_enable_openthread = false import("${chip_root}/src/platform/silabs/wifi/args.gni") sl_enable_test_event_trigger = false -chip_enable_ota_requestor = false +chip_enable_ota_requestor = true app_data_model = "${chip_root}/examples/rangehood-app/rangehood-app-common" diff --git a/examples/rangehood-app/silabs/include/AppConfig.h b/examples/rangehood-app/silabs/include/AppConfig.h index dff6ee6236f..ca13003a4df 100644 --- a/examples/rangehood-app/silabs/include/AppConfig.h +++ b/examples/rangehood-app/silabs/include/AppConfig.h @@ -25,7 +25,7 @@ #define APP_TASK_NAME "RangeHood" -#define BLE_DEV_NAME "SiLabs-RangeHood" +#define BLE_DEV_NAME "SiLabs-" APP_TASK_NAME // Time it takes in ms for the simulated actuator to move from one // state to another. diff --git a/examples/rangehood-app/silabs/include/AppTask.h b/examples/rangehood-app/silabs/include/AppTask.h index b186a377e7b..29321d4d6c2 100644 --- a/examples/rangehood-app/silabs/include/AppTask.h +++ b/examples/rangehood-app/silabs/include/AppTask.h @@ -89,7 +89,6 @@ class AppTask : public BaseApplication static void ActionInitiated(RangeHoodManager::Action_t aAction, int32_t aActor, uint8_t * value); static void ActionCompleted(RangeHoodManager::Action_t aAction); - static void LightActionEventHandler(AppEvent * aEvent); /** * @brief Override of BaseApplication::AppInit() virtual method, called by BaseApplication::Init() * @@ -98,13 +97,12 @@ class AppTask : public BaseApplication CHIP_ERROR AppInit() override; /** - * @brief PB0 Button event processing function - * Press and hold will trigger a factory reset timer start - * Press and release will restart BLEAdvertising if not commisionned + * @brief Handle FAN ON/OFF when BTN1 pressed * - * @param aEvent button event being processed + * @param aEvent event received */ - static void ButtonHandler(AppEvent * aEvent); + static void FanControlButtonHandler(AppEvent * aEvent); + // Work item executed on CHIP stack thread to toggle fan mode safely static void SetFanOnOff(intptr_t context); }; diff --git a/examples/rangehood-app/silabs/include/RangeHoodManager.h b/examples/rangehood-app/silabs/include/RangeHoodManager.h index e7c8946db7c..64b88de0353 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodManager.h +++ b/examples/rangehood-app/silabs/include/RangeHoodManager.h @@ -51,7 +51,7 @@ class RangeHoodManager RangeHoodManager() : mState(kState_OffCompleted), mActionInitiated_CB(nullptr), mActionCompleted_CB(nullptr), mAutoTurnOff(false), mAutoTurnOffDuration(0), mAutoTurnOffTimerArmed(false), mOffEffectArmed(false), mLightTimer(nullptr), - mFanMode(FanModeEnum::kOff), mSpeedMax(0), percentCurrent(0), speedCurrent(0), + mFanMode(FanModeEnum::kOff), percentCurrent(0), // initialize endpoint helpers with the required EndpointIds: mExtractorHoodEndpoint1(kExtractorHoodEndpoint1), mLightEndpoint2(kLightEndpoint2) {} @@ -91,11 +91,8 @@ class RangeHoodManager void HandleFanControlAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value); void PercentSettingWriteCallback(uint8_t aNewPercentSetting); - void SpeedSettingWriteCallback(uint8_t aNewSpeedSetting); void FanModeWriteCallback(FanModeEnum aNewFanMode); - void SetPercentSetting(Percent aNewPercentSetting); - void UpdateFanMode(); static void UpdateClusterState(intptr_t arg); @@ -110,13 +107,9 @@ class RangeHoodManager struct AttributeUpdateInfo { FanModeEnum fanMode; - uint8_t speedCurrent; uint8_t percentCurrent; - uint8_t speedSetting; uint8_t percentSetting; bool isPercentCurrent = false; - bool isSpeedCurrent = false; - bool isSpeedSetting = false; bool isFanMode = false; bool isPercentSetting = false; EndpointId endPoint; @@ -159,23 +152,20 @@ class RangeHoodManager static void OffEffectTimerEventHandler(AppEvent * aEvent); FanModeEnum mFanMode; - uint8_t mSpeedMax; uint8_t percentCurrent; - uint8_t speedCurrent; - // Fan Mode Limits - static constexpr int kFanModeLowLowerBound = 1; - static constexpr int kFanModeLowUpperBound = 3; - static constexpr int kFanModeMediumLowerBound = 4; - static constexpr int kFanModeMediumUpperBound = 7; - static constexpr int kFanModeHighLowerBound = 8; - static constexpr int kFanModeHighUpperBound = 10; + // Fan Mode Percent Mappings (since SPEED features are not enabled) + static constexpr uint8_t kFanModeOffPercent = 0; // Off: 0% + static constexpr uint8_t kFanModeLowPercent = 30; // Low: 30% + static constexpr uint8_t kFanModeMediumPercent = 60; // Medium: 60% + static constexpr uint8_t kFanModeHighPercent = 100; // High: 100% - static constexpr int kaLowestOffTrue = 0; - static constexpr int kaLowestOffFalse = 1; + // Step command minimum values (for aLowestOff parameter) + static constexpr uint8_t kaLowestOffTrue = 0; // Can step down to 0% (off) + static constexpr uint8_t kaLowestOffFalse = 1; // Can only step down to 1% (minimum on) + static constexpr uint8_t kStepSizePercent = 10; // Step by 10% increments DataModel::Nullable GetPercentSetting(); - DataModel::Nullable GetSpeedSetting(); static RangeHoodManager sRangeHoodMgr; diff --git a/examples/rangehood-app/silabs/include/RangeHoodUI.h b/examples/rangehood-app/silabs/include/RangeHoodUI.h index a456244ade7..e57a7ec0064 100644 --- a/examples/rangehood-app/silabs/include/RangeHoodUI.h +++ b/examples/rangehood-app/silabs/include/RangeHoodUI.h @@ -33,6 +33,4 @@ class RangeHoodUI private: static void DrawHeader(GLIB_Context_t * glibContext); static void DrawRangehoodStatus(GLIB_Context_t * glibContext); - static void DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, - uint32_t size); }; diff --git a/examples/rangehood-app/silabs/src/AppTask.cpp b/examples/rangehood-app/silabs/src/AppTask.cpp index d9f41c73ffb..ee27e85340b 100644 --- a/examples/rangehood-app/silabs/src/AppTask.cpp +++ b/examples/rangehood-app/silabs/src/AppTask.cpp @@ -150,12 +150,12 @@ void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) if (button == APP_ACTION_BUTTON && btnAction == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) { - button_event.Handler = ButtonHandler; + button_event.Handler = FanControlButtonHandler; AppTask::GetAppTask().PostEvent(&button_event); } else if (button == APP_FUNCTION_BUTTON) { - // Defer other button events to generic base handler (factory reset, etc.) + // Defer other button events to generic base handler button_event.Handler = BaseApplication::ButtonHandler; AppTask::GetAppTask().PostEvent(&button_event); } @@ -213,13 +213,16 @@ void AppTask::SetFanOnOff(intptr_t context) } } -void AppTask::ButtonHandler(AppEvent * aEvent) +void AppTask::FanControlButtonHandler(AppEvent * aEvent) { - // Distinguish between function and action buttons + /** + * Handle button press events for range hood control + * This function processes button events specifically for the action button (BTN1) + * which controls the fan operation in the range hood application. + */ if (aEvent->ButtonEvent.Action == static_cast(::chip::DeviceLayer::Silabs::SilabsPlatform::ButtonAction::ButtonPressed)) { - // Fan toggle using same button for now (could be separated if button id available) // Schedule fan mode toggle on CHIP stack thread to avoid direct access causing locking errors. chip::DeviceLayer::PlatformMgr().ScheduleWork(SetFanOnOff, 0); } diff --git a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp index 7f0530e0429..3c519178983 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodManager.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodManager.cpp @@ -45,7 +45,6 @@ RangeHoodManager RangeHoodManager::sRangeHoodMgr; CHIP_ERROR RangeHoodManager::Init() { - DeviceLayer::PlatformMgr().LockChipStack(); // Endpoint initializations VerifyOrReturnError(mExtractorHoodEndpoint1.Init() == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); @@ -66,11 +65,10 @@ CHIP_ERROR RangeHoodManager::Init() bool currentLedState; + DeviceLayer::PlatformMgr().LockChipStack(); // read current on/off value on light endpoint. OnOffServer::Instance().getOnOffValue(kLightEndpoint2, ¤tLedState); - chip::app::Clusters::FanControl::Attributes::SpeedMax::Get(kExtractorHoodEndpoint1, &mSpeedMax); - DataModel::Nullable percentSettingNullable = GetPercentSetting(); uint8_t percentSettingCB = percentSettingNullable.IsNull() ? 0 : percentSettingNullable.Value(); PercentSettingWriteCallback(percentSettingCB); @@ -325,35 +323,35 @@ Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId VerifyOrReturnError(aDirection != StepDirectionEnum::kUnknownEnumValue, Status::InvalidCommand); - // if aLowestOff is true, Step command can reduce the fan speed to 0, else 1. - uint8_t speedMin = aLowestOff ? kaLowestOffTrue : kaLowestOffFalse; + // if aLowestOff is true, Step command can reduce the fan to 0%, else 1%. + uint8_t percentMin = aLowestOff ? kaLowestOffTrue : kaLowestOffFalse; + uint8_t percentMax = 100; // Maximum percent value - DataModel::Nullable speedSettingNullable = GetSpeedSetting(); - - uint8_t curSpeedSetting = speedSettingNullable.IsNull() ? speedMin : speedSettingNullable.Value(); + DataModel::Nullable percentSettingNullable = GetPercentSetting(); + uint8_t curPercentSetting = percentSettingNullable.IsNull() ? percentMin : percentSettingNullable.Value(); - // increase or decrease the fan speed by one step + // increase or decrease the fan percent by step size switch (aDirection) { case StepDirectionEnum::kIncrease: { - if (curSpeedSetting >= mSpeedMax) + if (curPercentSetting >= percentMax) { - curSpeedSetting = aWrap ? speedMin : mSpeedMax; + curPercentSetting = aWrap ? percentMin : percentMax; } else { - curSpeedSetting++; + curPercentSetting = std::min(percentMax, static_cast(curPercentSetting + kStepSizePercent)); } break; } case StepDirectionEnum::kDecrease: { - if (curSpeedSetting <= speedMin) + if (curPercentSetting <= percentMin) { - curSpeedSetting = aWrap ? mSpeedMax : speedMin; + curPercentSetting = aWrap ? percentMax : percentMin; } else { - curSpeedSetting--; + curPercentSetting = std::max(percentMin, static_cast(curPercentSetting - kStepSizePercent)); } break; } @@ -362,9 +360,6 @@ Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId } } - // Convert SpeedSetting to PercentSetting - uint8_t curPercentSetting = ((static_cast(curSpeedSetting) * 100) / mSpeedMax); - AttributeUpdateInfo * data = chip::Platform::New(); data->percentSetting = curPercentSetting; data->endPoint = kExtractorHoodEndpoint1; @@ -382,18 +377,11 @@ Status RangeHoodManager::ProcessExtractorStepCommand(chip::EndpointId endpointId void RangeHoodManager::UpdateClusterState(intptr_t arg) { RangeHoodManager::AttributeUpdateInfo * data = reinterpret_cast(arg); - if (data->isSpeedCurrent) - { - chip::app::Clusters::FanControl::Attributes::SpeedCurrent::Set(data->endPoint, data->speedCurrent); - } - else if (data->isPercentCurrent) + + if (data->isPercentCurrent) { chip::app::Clusters::FanControl::Attributes::PercentCurrent::Set(data->endPoint, data->percentCurrent); } - else if (data->isSpeedSetting) - { - chip::app::Clusters::FanControl::Attributes::SpeedSetting::Set(data->endPoint, data->speedSetting); - } else if (data->isFanMode) { chip::app::Clusters::FanControl::Attributes::FanMode::Set(data->endPoint, data->fanMode); @@ -462,39 +450,35 @@ void RangeHoodManager::UpdateFanMode() void RangeHoodManager::FanModeWriteCallback(FanModeEnum aNewFanMode) { ChipLogDetail(NotSpecified, "RangeHoodManager::FanModeWriteCallback: %d", (uint8_t) aNewFanMode); - // Set Percent Settings, which will update the Speed Settings through callback. + // Set Percent Settings directly switch (aNewFanMode) { case FanModeEnum::kOff: { - if (speedCurrent != 0) + if (percentCurrent != kFanModeOffPercent) { - Percent percentSetting = 0; - SetPercentSetting(percentSetting); + SetPercentSetting(kFanModeOffPercent); } break; } case FanModeEnum::kLow: { - if (speedCurrent < kFanModeLowLowerBound || speedCurrent > kFanModeLowUpperBound) + if (percentCurrent != kFanModeLowPercent) { - Percent percentSetting = kFanModeLowUpperBound * mSpeedMax; - SetPercentSetting(percentSetting); + SetPercentSetting(kFanModeLowPercent); } break; } case FanModeEnum::kMedium: { - if (speedCurrent < kFanModeMediumLowerBound || speedCurrent > kFanModeMediumUpperBound) + if (percentCurrent != kFanModeMediumPercent) { - Percent percentSetting = kFanModeMediumLowerBound * mSpeedMax; - SetPercentSetting(percentSetting); + SetPercentSetting(kFanModeMediumPercent); } break; } case FanModeEnum::kOn: case FanModeEnum::kHigh: { - if (speedCurrent < kFanModeHighLowerBound || speedCurrent > kFanModeHighUpperBound) + if (percentCurrent != kFanModeHighPercent) { - Percent percentSetting = kFanModeHighLowerBound * mSpeedMax; - SetPercentSetting(percentSetting); + SetPercentSetting(kFanModeHighPercent); } break; } @@ -532,20 +516,6 @@ FanModeEnum RangeHoodManager::GetFanMode() return mFanMode; } -DataModel::Nullable RangeHoodManager::GetSpeedSetting() -{ - DataModel::Nullable speedSetting; - - Status status = chip::app::Clusters::FanControl::Attributes::SpeedSetting::Get(kExtractorHoodEndpoint1, speedSetting); - if (status != Status::Success) - { - ChipLogError(NotSpecified, "RangeHoodManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", - to_underlying(status)); - } - - return speedSetting; -} - DataModel::Nullable RangeHoodManager::GetPercentSetting() { DataModel::Nullable percentSetting; diff --git a/examples/rangehood-app/silabs/src/RangeHoodUI.cpp b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp index 82df227734a..37bcd97ce38 100644 --- a/examples/rangehood-app/silabs/src/RangeHoodUI.cpp +++ b/examples/rangehood-app/silabs/src/RangeHoodUI.cpp @@ -19,6 +19,7 @@ #include #include +#include "AppConfig.h" #include "AppTask.h" #include "RangeHoodManager.h" #include "RangeHoodUI.h" @@ -80,7 +81,7 @@ void RangeHoodUI::DrawHeader(GLIB_Context_t * glibContext) GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap); // Draw application name on a dedicated line below icons. - GLIB_drawStringOnLine(glibContext, "RangeHood-App", 3, GLIB_ALIGN_CENTER, 0, 0, true); + GLIB_drawStringOnLine(glibContext, APP_TASK_NAME, 3, GLIB_ALIGN_CENTER, 0, 0, true); #if SL_LCDCTRL_MUX sl_wfx_host_pre_lcd_spi_transfer(); #endif // SL_LCDCTRL_MUX @@ -125,31 +126,3 @@ void RangeHoodUI::DrawRangehoodStatus(GLIB_Context_t * glibContext) sl_wfx_host_post_lcd_spi_transfer(); #endif // SL_LCDCTRL_MUX } - -void RangeHoodUI::DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data, - uint32_t size) -{ - uint8_t x = initial_x, y = initial_y; - for (uint16_t i = 0; i < size; i++) - { - for (uint8_t mask = 0; mask < 8; mask++) - { - if (!(data[i] & (0x01 << mask))) - { - GLIB_drawPixel(glibContext, x, y); - } - // Check line changes - if (((x - initial_x) % width) == 0 && x != initial_x) - { - x = initial_x; - y++; - // Font is 8 bit align with paddings bits; - mask = 8; - } - else - { - x++; - } - } - } -} From 9774090c81cf044a3adccd8fd287dd7d567e3b56 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Fri, 31 Oct 2025 15:29:51 +0530 Subject: [PATCH 10/11] Removed duplicate file --- examples/rangehood-app/silabs/.gn copy | 29 -------------------------- 1 file changed, 29 deletions(-) delete mode 100644 examples/rangehood-app/silabs/.gn copy diff --git a/examples/rangehood-app/silabs/.gn copy b/examples/rangehood-app/silabs/.gn copy deleted file mode 100644 index fe0e637d199..00000000000 --- a/examples/rangehood-app/silabs/.gn copy +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2025 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build_overrides/build.gni") - -# The location of the build configuration file. -buildconfig = "${build_root}/config/BUILDCONFIG.gn" - -# CHIP uses angle bracket includes. -check_system_includes = true - -default_args = { - target_cpu = "arm" - target_os = "freertos" - chip_openthread_ftd = true - - import("//openthread.gni") -} \ No newline at end of file From 10571ae9d42b352dec62b2080b5ebed55ee8149d Mon Sep 17 00:00:00 2001 From: bhmanda-silabs Date: Fri, 31 Oct 2025 16:08:58 +0530 Subject: [PATCH 11/11] Resolved review comments --- .../rangehood-app-common/include/ExtractorHoodEndpoint.h | 2 +- .../rangehood-app/rangehood-app-common/src/LightEndpoint.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h index ce7e32ab50c..9a88f29f0d7 100644 --- a/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h +++ b/examples/rangehood-app/rangehood-app-common/include/ExtractorHoodEndpoint.h @@ -55,7 +55,7 @@ class FanDelegate : public FanControl::Delegate FanDelegate(EndpointId aEndpoint) : FanControl::Delegate(aEndpoint), mEndpoint(aEndpoint) {} protected: - EndpointId mEndpoint = 0; + EndpointId mEndpoint = kInvalidEndpointId; }; class ExtractorHoodEndpoint { diff --git a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp index 75823959953..f5188369e97 100644 --- a/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp +++ b/examples/rangehood-app/rangehood-app-common/src/LightEndpoint.cpp @@ -35,14 +35,18 @@ CHIP_ERROR LightEndpoint::Init() bool LightEndpoint::GetOnOffState() { bool state = false; + chip::DeviceLayer::PlatformMgr().LockChipStack(); OnOffServer::Instance().getOnOffValue(mEndpointId, &state); + chip::DeviceLayer::PlatformMgr().LockChipStack(); return state; } void LightEndpoint::SetOnOffState(bool state) { CommandId commandId = state ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id; + chip::DeviceLayer::PlatformMgr().LockChipStack(); auto status = OnOffServer::Instance().setOnOffValue(mEndpointId, commandId, false); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); if (status != Protocols::InteractionModel::Status::Success) { ChipLogError(AppServer, "ERR: updating on/off %x", to_underlying(status));