/* * * Copyright (c) 2021 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 #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #include #include "CommissionableInit.h" #include "Device.h" #include "main.h" #include #include #include #include #include using namespace chip; using namespace chip::app; using namespace chip::Credentials; using namespace chip::Inet; using namespace chip::Transport; using namespace chip::DeviceLayer; using namespace chip::app::Clusters; using namespace chip::app::Clusters::WindowCovering; //WindowCoveringManager sWindowCoveringManager; // using namespace chip::app::Clusters::WindowCovering::WindowCoveringManager; namespace { const int kNodeLabelSize = 32; // Current ZCL implementation of Struct uses a max-size array of 254 bytes const int kDescriptorAttributeArraySize = 254; EndpointId gCurrentEndpointId; EndpointId gFirstDynamicEndpointId; // Power source is on the same endpoint as the composed device Device * gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1]; std::vector gRooms; std::vector gActions; const int16_t minMeasuredValue = -27315; const int16_t maxMeasuredValue = 32766; const int16_t initialMeasuredValue = 100; // ENDPOINT DEFINITIONS: // ================================================================================= // // Endpoint definitions will be reused across multiple endpoints for every instance of the // endpoint type. // There will be no intrinsic storage for the endpoint attributes declared here. // Instead, all attributes will be treated as EXTERNAL, and therefore all reads // or writes to the attributes must be handled within the emberAfExternalAttributeWriteCallback // and emberAfExternalAttributeReadCallback functions declared herein. This fits // the typical model of a bridge, since a bridge typically maintains its own // state database representing the devices connected to it. // Device types for dynamic endpoints: TODO Need a generated file from ZAP to define these! // (taken from matter-devices.xml) #define DEVICE_TYPE_BRIDGED_NODE 0x0013 // (taken from lo-devices.xml) #define DEVICE_TYPE_LO_ON_OFF_LIGHT 0x0100 // (taken from matter-devices.xml) #define DEVICE_TYPE_POWER_SOURCE 0x0011 // (taken from matter-devices.xml) #define DEVICE_TYPE_TEMP_SENSOR 0x0302 #define DEVICE_TYPE_WINDOW_COVERING 0x0202 #define DEVICE_TYPE_LEVEL_CONTROL 0x0104 #define DEVICE_TYPE_COLOR_EXTEND_LIGHT 0x010D // Device Version for dynamic endpoints: #define DEVICE_VERSION_DEFAULT 1 // --------------------------------------------------------------------------- // // LIGHT ENDPOINT: contains the following clusters: // - On/Off // - Descriptor // - Bridged Device Basic Information // Declare On/Off cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(onOffAttrs) DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::OnOff::Id, BOOLEAN, 1, 0), /* on/off */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // Declare Descriptor cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs) DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */ DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */ DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */ DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // Declare Bridged Device Basic Information cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs) DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */ DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0), /* Reachable */ DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* feature map */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(windowCoveringAttrs) DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::Type::Id, ENUM8, 1, 0), /* Type */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionLift::Id, INT16U, 2, 0), /* Current Position Lift */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionTilt::Id, INT16U, 2, 0), /* Current Position Tilt */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::ConfigStatus::Id, BITMAP8, 1, 0), /* Config Status */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionLiftPercentage::Id, PERCENT, 1, 0), /* Current Position Lift Percentage */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionTiltPercentage::Id, PERCENT, 1, 0), /* Current Position Tilt Percentage */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::OperationalStatus::Id, BITMAP8, 1, 0), /* Operational Status */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::TargetPositionLiftPercent100ths::Id, INT16U, 2, 0), /* Target Position Lift */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::TargetPositionTiltPercent100ths::Id, INT16U, 2, 0), /* Target Position Tilt */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::EndProductType::Id, ENUM8, 1, 0), /* End Product Type */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::Mode::Id, ENUM8, 1, 0), /* Mode */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::SafetyStatus::Id, BITMAP16, 1, 0), /* Safety Status */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::EndProductType::Id, ENUM8, 1, 0), /* End Product Features */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionTiltPercent100ths::Id, PERCENT100THS, 2, 0), /* Current Position Lift Percentage 100ths */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::CurrentPositionLiftPercent100ths::Id, PERCENT100THS, 2, 0), /* Current Position Tilt Percentage 100ths */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::InstalledOpenLimitLift::Id, INT16U, 2, 0), /* Installed Open Limit Lift */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::InstalledClosedLimitLift::Id, INT16U, 2, 0), /* Installed Closed Limit Lift */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::InstalledOpenLimitTilt::Id, INT16U, 2, 0), /* Installed Open Limit Tilt */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::InstalledClosedLimitTilt::Id, INT16U, 2, 0), /* Installed Closed Limit Tilt */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE(WindowCovering::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(colorExtendAttrs) DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CurrentHue::Id, INT8U, 1, 0), /* Current Hue */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CurrentSaturation::Id, INT8U, 1, 0), /* Current Saturation */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::RemainingTime::Id, INT16U, 2, 0), /* Remaining Time */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CurrentX::Id, INT16U, 2, 0), /* Current X */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CurrentY::Id, INT16U, 2, 0), /* Current Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::DriftCompensation::Id, ENUM8, 1, 0), /* Drift Compensation */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CompensationText::Id, CHAR_STRING, 255, 0), /* Compensation Text */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorTemperatureMireds::Id, INT16U, 2, 0), /* Color Temperature */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorMode::Id, ENUM8, 1, 0), /* Color Mode */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Options::Id, BITMAP8, 1, 0), /* Options */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::NumberOfPrimaries::Id, INT8U, 1, 0), /* Number Of Primaries */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary1X::Id, INT16U, 2, 0), /* Primary1 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary1Y::Id, INT16U, 2, 0), /* Primary1 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary1Intensity::Id, INT8U, 1, 0), /* Primary1 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary2X::Id, INT16U, 2, 0), /* Primary2 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary2Y::Id, INT16U, 2, 0), /* Primary2 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary2Intensity::Id, INT8U, 1, 0), /* Primary2 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary3X::Id, INT16U, 2, 0), /* Primary3 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary3Y::Id, INT16U, 2, 0), /* Primary3 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary3Intensity::Id, INT8U, 1, 0), /* Primary3 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary4X::Id, INT16U, 2, 0), /* Primary4 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary4Y::Id, INT16U, 2, 0), /* Primary4 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary4Intensity::Id, INT8U, 1, 0), /* Primary4 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary5X::Id, INT16U, 2, 0), /* Primary5 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary5Y::Id, INT16U, 2, 0), /* Primary5 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary5Intensity::Id, INT8U, 1, 0), /* Primary5 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary6X::Id, INT16U, 2, 0), /* Primary6 X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary6Y::Id, INT16U, 2, 0), /* Primary6 Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::Primary6Intensity::Id, INT8U, 1, 0), /* Primary6 Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::WhitePointX::Id, INT16U, 2, 0), /* White Point X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::WhitePointY::Id, INT16U, 2, 0), /* White Point Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointRX::Id, INT16U, 2, 0), /* Color Point R X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointRY::Id, INT16U, 2, 0), /* Color Point R Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointRIntensity::Id, INT8U, 1, 0), /* Color Point R Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointGX::Id, INT16U, 2, 0), /* Color Point G X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointGY::Id, INT16U, 2, 0), /* Color Point G Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointGIntensity::Id, INT8U, 1, 0), /* Color Point G Intensity */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointBX::Id, INT16U, 2, 0), /* Color Point B X */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointBY::Id, INT16U, 2, 0), /* Color Point B Y */ // DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorPointBIntensity::Id, INT8U, 1, 0), /* Color Point B Intensity */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::EnhancedCurrentHue::Id, INT16U, 2, 0), /* Enhanced Current Hue */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::EnhancedColorMode::Id, ENUM8, 1, 0), /* Enhanced Color Mode */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorLoopActive::Id, INT8U, 1, 0), /* Color Loop Active */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorLoopDirection::Id, INT8U, 1, 0), /* Color Loop Direction */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorLoopTime::Id, INT16U, 2, 0), /* Color Loop Time */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorCapabilities::Id, BITMAP16, 2, 0), /* Color Capabilities */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorTempPhysicalMinMireds::Id, INT16U, 2, 0), /* Color Temp Physical Min */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ColorTempPhysicalMaxMireds::Id, INT16U, 2, 0), /* Color Temp Physical Max */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::CoupleColorTempToLevelMinMireds::Id, INT16U, 2, 0), /* Couple Color Temp To Level Min Mireds */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::StartUpColorTemperatureMireds::Id, INT16U, 2, 0), /* Start Up Color Temperature */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE(ColorControl::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(onOffColorAttrs) DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::OnOff::Id, BOOLEAN, 1, 0), /* on/off */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::GlobalSceneControl::Id, BOOLEAN, 1, 0), /* Global Scene Control */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::OnTime::Id, INT16U, 2, 0), /* On Time */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::OffWaitTime::Id, INT16U, 2, 0), /* Off Wait Time */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::StartUpOnOff::Id, BOOLEAN, 1, 0), /* Start Up On/Off */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(levelControlAttrs) DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::CurrentLevel::Id, INT8U, 1, 0), /* Current Level */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::RemainingTime::Id, INT16U, 2, 0), /* Remaining Time */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::MinLevel::Id, INT8U, 1, 0), /* Min Level */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::Options::Id, BITMAP8, 1, 0), /* Options */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::StartUpCurrentLevel::Id, INT8U, 1, 0), /* Start Up Current Level */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::CurrentFrequency::Id, INT16U, 2, 0), /* Current Frequency */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::MinFrequency::Id, INT16U, 2, 0), /* Min Frequency */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::MaxFrequency::Id, INT16U, 2, 0), /* Max Frequency */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::OnOffTransitionTime::Id, INT16U, 2, 0), /* On/Off Transition Time */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::OnLevel::Id, INT8U, 1, 0), /* On Level */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::OnTransitionTime::Id, INT16U, 2, 0), /* On Transition Time */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::OffTransitionTime::Id, INT16U, 2, 0), /* Off Transition Time */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::DefaultMoveRate::Id, INT16U, 2, 0), /* Default Move Rate */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE(LevelControl::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(scenesManagerAttrs) DECLARE_DYNAMIC_ATTRIBUTE(ScenesManagement::Attributes::SceneTableSize::Id, INT16U, 2, 0), /* Scene Table Size */ DECLARE_DYNAMIC_ATTRIBUTE(ScenesManagement::Attributes::FabricSceneInfo::Id, ARRAY, 0, 0), /* Fabric Scene Info */ DECLARE_DYNAMIC_ATTRIBUTE(ScenesManagement::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE(ScenesManagement::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(groupsManagerAttrs) DECLARE_DYNAMIC_ATTRIBUTE(Groups::Attributes::NameSupport::Id, BITMAP8, 1, 0), /* Name Support */ DECLARE_DYNAMIC_ATTRIBUTE(Groups::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE(Groups::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(IdentifyAttrs) DECLARE_DYNAMIC_ATTRIBUTE(Identify::Attributes::IdentifyTime::Id, INT16U, 2, 0), /* Identify Time */ DECLARE_DYNAMIC_ATTRIBUTE(Identify::Attributes::IdentifyType::Id, ENUM8, 1, 0), /* Identify Type */ DECLARE_DYNAMIC_ATTRIBUTE(Identify::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* Feature Map */ DECLARE_DYNAMIC_ATTRIBUTE(Identify::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* Cluster Revision */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // Declare Cluster List for Bridged Light endpoint // TODO: It's not clear whether it would be better to get the command lists from // the ZAP config on our last fixed endpoint instead. constexpr CommandId onOffIncomingCommands[] = { app::Clusters::OnOff::Commands::Off::Id, app::Clusters::OnOff::Commands::On::Id, app::Clusters::OnOff::Commands::Toggle::Id, app::Clusters::OnOff::Commands::OffWithEffect::Id, app::Clusters::OnOff::Commands::OnWithRecallGlobalScene::Id, app::Clusters::OnOff::Commands::OnWithTimedOff::Id, kInvalidCommandId, }; constexpr CommandId levelControlIncomingCommands[] = { app::Clusters::LevelControl::Commands::Move::Id, app::Clusters::LevelControl::Commands::MoveToLevel::Id, app::Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id, app::Clusters::LevelControl::Commands::MoveWithOnOff::Id, app::Clusters::LevelControl::Commands::Step::Id, app::Clusters::LevelControl::Commands::StepWithOnOff::Id, app::Clusters::LevelControl::Commands::Stop::Id, app::Clusters::LevelControl::Commands::StopWithOnOff::Id, kInvalidCommandId, }; constexpr CommandId windowIncomminCommands[] = { app::Clusters::WindowCovering::Commands::UpOrOpen::Id, app::Clusters::WindowCovering::Commands::DownOrClose::Id, app::Clusters::WindowCovering::Commands::StopMotion::Id, app::Clusters::WindowCovering::Commands::GoToLiftPercentage::Id, app::Clusters::WindowCovering::Commands::GoToLiftValue::Id, app::Clusters::WindowCovering::Commands::GoToTiltPercentage::Id, app::Clusters::WindowCovering::Commands::GoToTiltValue::Id, kInvalidCommandId, }; constexpr CommandId colorExtendIncomingCommands[] { app::Clusters::ColorControl::Commands::MoveToHue::Id, app::Clusters::ColorControl::Commands::MoveHue::Id, app::Clusters::ColorControl::Commands::StepHue::Id, app::Clusters::ColorControl::Commands::MoveToSaturation::Id, app::Clusters::ColorControl::Commands::MoveSaturation::Id, app::Clusters::ColorControl::Commands::StepSaturation::Id, app::Clusters::ColorControl::Commands::MoveToHueAndSaturation::Id, app::Clusters::ColorControl::Commands::MoveToColor::Id, app::Clusters::ColorControl::Commands::MoveColor::Id, app::Clusters::ColorControl::Commands::StepColor::Id, app::Clusters::ColorControl::Commands::MoveToColorTemperature::Id, app::Clusters::ColorControl::Commands::MoveColorTemperature::Id, app::Clusters::ColorControl::Commands::StepColorTemperature::Id, kInvalidCommandId, }; constexpr CommandId groupIncommingCommands[]{ app::Clusters::Groups::Commands::AddGroup::Id, app::Clusters::Groups::Commands::AddGroupIfIdentifying::Id, app::Clusters::Groups::Commands::GetGroupMembership::Id, app::Clusters::Groups::Commands::RemoveGroup::Id, app::Clusters::Groups::Commands::RemoveAllGroups::Id, app::Clusters::Groups::Commands::AddGroupResponse::Id, app::Clusters::Groups::Commands::ViewGroup::Id, app::Clusters::Groups::Commands::GetGroupMembershipResponse::Id, app::Clusters::Groups::Commands::RemoveGroupResponse::Id, kInvalidCommandId, }; constexpr CommandId identityIncomingCommands[]{ app::Clusters::Identify::Commands::Identify::Id, app::Clusters::Identify::Commands::TriggerEffect::Id, kInvalidCommandId, }; constexpr CommandId scenceIncommingCommands[]{ app::Clusters::ScenesManagement::Commands::AddScene::Id, app::Clusters::ScenesManagement::Commands::ViewScene::Id, app::Clusters::ScenesManagement::Commands::CopyScene::Id, kInvalidCommandId, }; DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedLightClusters) DECLARE_DYNAMIC_CLUSTER(OnOff::Id, onOffAttrs, ZAP_CLUSTER_MASK(SERVER), onOffIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedWindowCoveringClusters) DECLARE_DYNAMIC_CLUSTER(WindowCovering::Id, windowCoveringAttrs, ZAP_CLUSTER_MASK(SERVER), windowIncomminCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedColorExtendClusters) DECLARE_DYNAMIC_CLUSTER(ColorControl::Id, colorExtendAttrs, ZAP_CLUSTER_MASK(SERVER), colorExtendIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(OnOff::Id, onOffColorAttrs, ZAP_CLUSTER_MASK(SERVER), onOffIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(LevelControl::Id, levelControlAttrs, ZAP_CLUSTER_MASK(SERVER), levelControlIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Identify::Id, IdentifyAttrs, ZAP_CLUSTER_MASK(SERVER), identityIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(ScenesManagement::Id, scenesManagerAttrs, ZAP_CLUSTER_MASK(SERVER), scenceIncommingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Groups::Id, groupsManagerAttrs, ZAP_CLUSTER_MASK(SERVER), groupIncommingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedLevelControlClusters) DECLARE_DYNAMIC_CLUSTER(LevelControl::Id, levelControlAttrs, ZAP_CLUSTER_MASK(SERVER), levelControlIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(OnOff::Id, onOffColorAttrs, ZAP_CLUSTER_MASK(SERVER), onOffIncomingCommands, nullptr), DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; // --------------------------------------------------------------------------- DECLARE_DYNAMIC_ENDPOINT(bridgedColorExtendEndpoint, bridgedColorExtendClusters); DataVersion gColorExtendDataVersions[ArraySize(bridgedColorExtendClusters)]; DeviceColorControl ColorExtend1("Color Extend 1", "Room 1", 0,0,0); DECLARE_DYNAMIC_ENDPOINT(bridgedLevelControlEndpoint, bridgedLevelControlClusters); DataVersion gLevelControlDataVersions[ArraySize(bridgedLevelControlClusters)]; DeviceLevelControl LevelControl1("Level Control 1", "Room 1",10); DECLARE_DYNAMIC_ENDPOINT(bridgedWindowCoveringEndpoint, bridgedWindowCoveringClusters); DataVersion gWindowCoveringDataVersions[ArraySize(bridgedWindowCoveringClusters)]; DeviceWindowCovering WindowCovering1("Window Covering 1", "Room 1", 100, 100 ,100); // Declare Bridged Light endpoint DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters); DataVersion gLight1DataVersions[ArraySize(bridgedLightClusters)]; DataVersion gLight2DataVersions[ArraySize(bridgedLightClusters)]; DeviceOnOff Light1("Light 1", "Office"); DeviceOnOff Light2("Light 2", "Office"); DeviceTempSensor TempSensor1("TempSensor 1", "Office", minMeasuredValue, maxMeasuredValue, initialMeasuredValue); DeviceTempSensor TempSensor2("TempSensor 2", "Office", minMeasuredValue, maxMeasuredValue, initialMeasuredValue); DeviceTempSensor ComposedTempSensor1("Composed TempSensor 1", "Bedroom", minMeasuredValue, maxMeasuredValue, initialMeasuredValue); DeviceTempSensor ComposedTempSensor2("Composed TempSensor 2", "Bedroom", minMeasuredValue, maxMeasuredValue, initialMeasuredValue); // Declare Bridged endpoints used for Action clusters DataVersion gActionLight1DataVersions[ArraySize(bridgedLightClusters)]; DataVersion gActionLight2DataVersions[ArraySize(bridgedLightClusters)]; DataVersion gActionLight3DataVersions[ArraySize(bridgedLightClusters)]; DataVersion gActionLight4DataVersions[ArraySize(bridgedLightClusters)]; DeviceOnOff ActionLight1("Action Light 1", "Room 1"); DeviceOnOff ActionLight2("Action Light 2", "Room 1"); DeviceOnOff ActionLight3("Action Light 3", "Room 2"); DeviceOnOff ActionLight4("Action Light 4", "Room 2"); Room room1("Room 1", 0xE001, Actions::EndpointListTypeEnum::kRoom, true); Room room2("Room 2", 0xE002, Actions::EndpointListTypeEnum::kRoom, true); Room room3("Zone 3", 0xE003, Actions::EndpointListTypeEnum::kZone, false); Action action1(0x1001, "Room 1 On", Actions::ActionTypeEnum::kAutomation, 0xE001, 0x1, Actions::ActionStateEnum::kInactive, true); Action action2(0x1002, "Turn On Room 2", Actions::ActionTypeEnum::kAutomation, 0xE002, 0x01, Actions::ActionStateEnum::kInactive, true); Action action3(0x1003, "Turn Off Room 1", Actions::ActionTypeEnum::kAutomation, 0xE003, 0x01, Actions::ActionStateEnum::kInactive, false); DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(tempSensorAttrs) DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MeasuredValue::Id, INT16S, 2, 0), /* Measured Value */ DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MinMeasuredValue::Id, INT16S, 2, 0), /* Min Measured Value */ DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MaxMeasuredValue::Id, INT16S, 2, 0), /* Max Measured Value */ DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */ DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // --------------------------------------------------------------------------- // // TEMPERATURE SENSOR ENDPOINT: contains the following clusters: // - Temperature measurement // - Descriptor // - Bridged Device Basic Information DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedTempSensorClusters) DECLARE_DYNAMIC_CLUSTER(TemperatureMeasurement::Id, tempSensorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER_LIST_END; // Declare Bridged Light endpoint DECLARE_DYNAMIC_ENDPOINT(bridgedTempSensorEndpoint, bridgedTempSensorClusters); DataVersion gTempSensor1DataVersions[ArraySize(bridgedTempSensorClusters)]; DataVersion gTempSensor2DataVersions[ArraySize(bridgedTempSensorClusters)]; // --------------------------------------------------------------------------- // // COMPOSED DEVICE ENDPOINT: contains the following clusters: // - Descriptor // - Bridged Device Basic Information // - Power source // Composed Device Configuration DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(powerSourceAttrs) DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::BatChargeLevel::Id, ENUM8, 1, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::BatReplacementNeeded::Id, BOOLEAN, 1, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::BatReplaceability::Id, ENUM8, 1, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::Order::Id, INT8U, 1, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::Status::Id, ENUM8, 1, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::Description::Id, CHAR_STRING, 32, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::EndpointList::Id, ARRAY, 0, 0), DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::FeatureMap::Id, BITMAP32, 4, 0), DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedComposedDeviceClusters) DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(PowerSource::Id, powerSourceAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER_LIST_END; DECLARE_DYNAMIC_ENDPOINT(bridgedComposedDeviceEndpoint, bridgedComposedDeviceClusters); DataVersion gComposedDeviceDataVersions[ArraySize(bridgedComposedDeviceClusters)]; DataVersion gComposedTempSensor1DataVersions[ArraySize(bridgedTempSensorClusters)]; DataVersion gComposedTempSensor2DataVersions[ArraySize(bridgedTempSensorClusters)]; } // namespace // REVISION DEFINITIONS: // ================================================================================= #define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) #define ZCL_FIXED_LABEL_CLUSTER_REVISION (1u) #define ZCL_ON_OFF_CLUSTER_REVISION (5u) #define ZCL_WINDOW_COVERING_CLUSTER_REVISION (1u) #define ZCL_TEMPERATURE_SENSOR_CLUSTER_REVISION (1u) #define ZCL_TEMPERATURE_SENSOR_FEATURE_MAP (0u) #define ZCL_POWER_SOURCE_CLUSTER_REVISION (2u) #define ZCL_COLOR_CONTROL_CLUSTER_REVISION (6u) #define ZCL_LEVEL_CONTROL_CLUSTER_REVISION (5u) // --------------------------------------------------------------------------- int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, const Span & deviceTypeList, const Span & dataVersionStorage, chip::EndpointId parentEndpointId = chip::kInvalidEndpointId) { uint8_t index = 0; while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) { if (nullptr == gDevices[index]) { gDevices[index] = dev; CHIP_ERROR err; while (true) { // Todo: Update this to schedule the work rather than use this lock DeviceLayer::StackLock lock; dev->SetEndpointId(gCurrentEndpointId); dev->SetParentEndpointId(parentEndpointId); err = emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId); if (err == CHIP_NO_ERROR){ // { // if(gCurrentEndpointId == 13) // { // ChipLogAutomation("Adding Window Covering Cluster to endpoint %d", gCurrentEndpointId); // chip::BitMask configStatus = ConfigStatusGet(gCurrentEndpointId); // configStatus.Set(ConfigStatus::kLiftEncoderControlled); // configStatus.Set(ConfigStatus::kTiltEncoderControlled); // ConfigStatusSet(gCurrentEndpointId, configStatus); // Clusters::WindowCovering::SetDefaultDelegate(gCurrentEndpointId, &sWindowCoveringManager); // Clusters::WindowCovering::ConfigStatusUpdateFeatures(gCurrentEndpointId); // Clusters::WindowCovering::ConfigStatusUpdateFeatures(gCurrentEndpointId); // } if(gCurrentEndpointId == 3) { ChipLogAutomation("Adding Color Control Cluster to endpoint %d", gCurrentEndpointId); DeviceColorControl* color = static_cast(dev); color->InitColorControl(); DeviceLevelControl* level = static_cast(dev); level->SetCurrentLevel(100); } // { // } ChipLogProgress(DeviceLayer, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(), gCurrentEndpointId, index); return index; } if (err != CHIP_ERROR_ENDPOINT_EXISTS) { return -1; } // Handle wrap condition if (++gCurrentEndpointId < gFirstDynamicEndpointId) { gCurrentEndpointId = gFirstDynamicEndpointId; } } } index++; } ChipLogProgress(DeviceLayer, "Failed to add dynamic endpoint: No endpoints available!"); return -1; } int RemoveDeviceEndpoint(Device * dev) { uint8_t index = 0; while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) { if (gDevices[index] == dev) { // Todo: Update this to schedule the work rather than use this lock DeviceLayer::StackLock lock; // Silence complaints about unused ep when progress logging // disabled. [[maybe_unused]] EndpointId ep = emberAfClearDynamicEndpoint(index); gDevices[index] = nullptr; ChipLogProgress(DeviceLayer, "Removed device %s from dynamic endpoint %d (index=%d)", dev->GetName(), ep, index); return index; } index++; } return -1; } std::vector GetEndpointListInfo(chip::EndpointId parentId) { std::vector infoList; for (auto room : gRooms) { if (room->getIsVisible()) { EndpointListInfo info(room->getEndpointListId(), room->getName(), room->getType()); int index = 0; while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) { if ((gDevices[index] != nullptr) && (gDevices[index]->GetParentEndpointId() == parentId)) { std::string location; if (room->getType() == Actions::EndpointListTypeEnum::kZone) { location = gDevices[index]->GetZone(); } else { location = gDevices[index]->GetLocation(); } if (room->getName().compare(location) == 0) { info.AddEndpointId(gDevices[index]->GetEndpointId()); } } index++; } if (info.GetEndpointListSize() > 0) { infoList.push_back(info); } } } return infoList; } std::vector GetActionListInfo(chip::EndpointId parentId) { return gActions; } Protocols::InteractionModel::Status HandleReadBridgedDeviceBasicAttribute(Device * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) { using namespace BridgedDeviceBasicInformation::Attributes; ChipLogProgress(DeviceLayer, "HandleReadBridgedDeviceBasicAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); if ((attributeId == Reachable::Id) && (maxReadLength == 1)) { *buffer = dev->IsReachable() ? 1 : 0; } else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32)) { MutableByteSpan zclNameSpan(buffer, maxReadLength); MakeZclCharString(zclNameSpan, dev->GetName()); } else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2)) { uint16_t rev = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION; memcpy(buffer, &rev, sizeof(rev)); } else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4)) { uint32_t featureMap = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP; memcpy(buffer, &featureMap, sizeof(featureMap)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadOnOffAttribute(DeviceOnOff * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) { ChipLogProgress(DeviceLayer, "HandleReadOnOffAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); if ((attributeId == OnOff::Attributes::OnOff::Id) && (maxReadLength == 1)) { *buffer = dev->IsOn() ? 1 : 0; } else if ((attributeId == OnOff::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) { uint16_t rev = ZCL_ON_OFF_CLUSTER_REVISION; memcpy(buffer, &rev, sizeof(rev)); } else if ((attributeId == OnOff::Attributes::GlobalSceneControl::Id) && (maxReadLength == 1)) { uint8_t globalSceneControl = 0x01; memcpy(buffer, &globalSceneControl, sizeof(globalSceneControl)); } else if ((attributeId == OnOff::Attributes::OnTime::Id) && (maxReadLength == 2)) { uint16_t onTime = 0; memcpy(buffer, &onTime, sizeof(onTime)); } else if ((attributeId == OnOff::Attributes::OffWaitTime::Id) && (maxReadLength == 2)) { uint16_t offWaitTime = 0; memcpy(buffer, &offWaitTime, sizeof(offWaitTime)); } else if ((attributeId == OnOff::Attributes::StartUpOnOff::Id) && (maxReadLength == 1)) { uint8_t startUpOnOff = 0xFF; memcpy(buffer, &startUpOnOff, sizeof(startUpOnOff)); } else if ((attributeId == OnOff::Attributes::FeatureMap::Id) && (maxReadLength == 4)) { uint32_t featureMap = 0x01; memcpy(buffer, &featureMap, sizeof(featureMap)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadWindowCoveringAttribute(DeviceWindowCovering * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) { ChipLogProgress(DeviceLayer, "HandleReadWindowCoveringAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); if((attributeId == WindowCovering::Attributes::Mode::Id) && (maxReadLength == 1)) { *buffer = chip::to_underlying( dev->GetMode()); }else if((attributeId == WindowCovering::Attributes::FeatureMap::Id) && (maxReadLength == 4)) { ChipLogProgress(DeviceLayer, "HandleReadWindowCoveringAttribute: FeatureMap"); BitMask FeatureMap; FeatureMap.Set(Feature::kLift); FeatureMap.Set(Feature::kPositionAwareLift); uint32_t featureMap = FeatureMap.Raw(); memcpy(buffer, &featureMap, sizeof(featureMap)); }else if((attributeId == WindowCovering::Attributes::ConfigStatus::Id) && (maxReadLength ==1)){ *buffer = 0x8; } else if ((attributeId == WindowCovering::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) { uint16_t rev = ZCL_WINDOW_COVERING_CLUSTER_REVISION; memcpy(buffer, &rev, sizeof(rev)); }else if ((attributeId == WindowCovering::Attributes::OperationalStatus::Id) && (maxReadLength == 1)) { //ChipLogAutomation("HandleReadWindowCoveringAttribute: OperationalStatus"); // WindowCovering::OperationalState opState = ComputeOperationalState(dev->GetTargetPositionLiftPercentage(), dev->GetCurrentPositionLiftPercentage()); // ChipLogAutomation("HandleReadWindowCoveringAttribute: OperationalStatus: target: %d, current: %d, opState: %d", dev->GetTargetPositionLiftPercentage(), dev->GetCurrentPositionLiftPercentage(), opState); //memcpy(buffer, &opState, sizeof(opState)); } else if ((attributeId == WindowCovering::Attributes::TargetPositionLiftPercent100ths::Id) && (maxReadLength == 2)){ uint16_t target = dev->GetTargetPositionLiftPercentage(); ChipLogAutomation("HandleReadWindowCoveringAttribute: TargetPositionLiftPercent100ths: %d", target); memcpy(buffer, &target, sizeof(target)); } else if ((attributeId == WindowCovering::Attributes::CurrentPositionLiftPercentage::Id) && (maxReadLength == 2)){ uint16_t current = dev->GetCurrentPositionLiftPercentage(); ChipLogAutomation("HandleReadWindowCoveringAttribute: CurrentPositionLiftPercentage: %d", current); memcpy(buffer, ¤t, sizeof(current)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadColorControlAttribute(DeviceColorControl * dev, chip::AttributeId attributeId, uint8_t *buffer , uint16_t maxReadLength){ ChipLogProgress(DeviceLayer, "HandleReadColorControlAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); if((attributeId == ColorControl::Attributes::FeatureMap::Id) && (maxReadLength == 4)) { // ChipLogProgress(DeviceLayer, "HandleReadColorControlAttribute: FeatureMap"); // uint32_t featureMap = 0x1F; // memcpy(buffer, &featureMap, sizeof(featureMap)); } if((attributeId == ColorControl::Attributes::CurrentHue::Id) && (maxReadLength == 1)) { //uint8_t hue = dev->GetCurrentHue(); // ChipLogAutomation("HandleReadColorControlAttribute: CurrentHue: %d", hue); // memcpy(buffer, &hue, sizeof(hue)); }else if((attributeId == ColorControl::Attributes::CurrentSaturation::Id) && (maxReadLength == 1)) { // uint8_t saturation = dev->GetCurrentSaturation(); // ChipLogAutomation("HandleReadColorControlAttribute: CurrentSaturation: %d", saturation); // memcpy(buffer, &saturation, sizeof(saturation)); }else if((attributeId == ColorControl::Attributes::ColorTemperatureMireds::Id) && (maxReadLength == 2)) { // uint16_t temperature = dev->GetCurrentTemperatureMireds(); // ChipLogAutomation("HandleReadColorControlAttribute: ColorTemperatureMireds: %d", temperature); // memcpy(buffer, &temperature, sizeof(temperature)); } else if((attributeId == ColorControl::Attributes::CurrentX::Id) && (maxReadLength==2)){ // uint16_t currentX = dev->GetCurrentX(); // ChipLogAutomation("HandleReadColorControlAttribute: CurrentX: %d", currentX); // memcpy(buffer, ¤tX, sizeof(currentX)); } else if((attributeId == ColorControl::Attributes::CurrentY::Id) && (maxReadLength==2)){ // uint16_t currentY = dev->GetCurrentY(); // ChipLogAutomation("HandleReadColorControlAttribute: CurrentY: %d", currentY); // memcpy(buffer, ¤tY, sizeof(currentY)); } else if((attributeId == ColorControl ::Attributes::ColorMode::Id) && (maxReadLength = 1)){ // uint8_t colorMode = dev->GetColorMode(); // ChipLogAutomation("HandleReadColorControlAttribute: ColorMode: %d", colorMode); // memcpy(buffer, &colorMode, sizeof(colorMode)); } else if((attributeId == ColorControl::Attributes::EnhancedCurrentHue::Id) && (maxReadLength == 2)) { // uint16_t hue = 0; // ChipLogAutomation("HandleReadColorControlAttribute: EnhancedCurrentHue: %d", hue); // memcpy(buffer, &hue, sizeof(hue)); } else if((attributeId == ColorControl::Attributes::EnhancedColorMode::Id) && (maxReadLength == 1)) { // uint8_t colorMode = 0x01; // ChipLogAutomation("HandleReadColorControlAttribute: EnhancedColorMode: %d", colorMode); // memcpy(buffer, &colorMode, sizeof(colorMode)); } else if((attributeId == ColorControl::Attributes::ColorLoopActive::Id) && (maxReadLength == 1)) { // uint8_t active = 0x00; // ChipLogAutomation("HandleReadColorControlAttribute: ColorLoopActive: %d", active); // memcpy(buffer, &active, sizeof(active)); } else if((attributeId == ColorControl::Attributes::ColorLoopDirection::Id) && (maxReadLength == 1)) { // uint8_t direction = 0x00; // ChipLogAutomation("HandleReadColorControlAttribute: ColorLoopDirection: %d", direction); // memcpy(buffer, &direction, sizeof(direction)); } else if((attributeId == ColorControl::Attributes::ColorLoopTime::Id) && (maxReadLength == 2)) { // uint16_t time = 0x0019; // ChipLogAutomation("HandleReadColorControlAttribute: ColorLoopTime: %d", time); // memcpy(buffer, &time, sizeof(time)); } else if((attributeId == ColorControl::Attributes::ColorLoopStartEnhancedHue::Id) && (maxReadLength == 2)){ // uint16_t hue = 0x2300; // ChipLogAutomation("HandleReadColorControlAttribute: ColorLoopStartEnhancedHue: %d", hue); // memcpy(buffer, &hue, sizeof(hue)); } else if((attributeId == ColorControl::Attributes::ColorLoopStoredEnhancedHue::Id) && (maxReadLength == 2)){ // uint16_t hue = 0x0000; // ChipLogAutomation("HandleReadColorControlAttribute: ColorLoopStoredEnhancedHue: %d", hue); // memcpy(buffer, &hue, sizeof(hue)); } else if((attributeId == ColorControl::Attributes::RemainingTime::Id) && (maxReadLength == 2)) { // uint16_t time = 0; // ChipLogAutomation("HandleReadColorControlAttribute: RemainingTime: %d", time); // memcpy(buffer, &time, sizeof(time)); }else if ((attributeId == ColorControl::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) { // uint16_t rev = ZCL_COLOR_CONTROL_CLUSTER_REVISION; // memcpy(buffer, &rev, sizeof(rev)); } else if((attributeId == ColorControl::Attributes::ColorCapabilities::Id) && (maxReadLength == 2)) { // BitMask colorCapa; // colorCapa.Set(ColorControl::ColorCapabilities::kHueSaturationSupported); // colorCapa.Set(ColorControl::ColorCapabilities::kColorTemperatureSupported); // colorCapa.Set(ColorControl::ColorCapabilities::kEnhancedHueSupported); // colorCapa.Set(ColorControl::ColorCapabilities::kColorLoopSupported); // colorCapa.Set(ColorControl::ColorCapabilities::kXYAttributesSupported); // uint32_t color = 0x1F; // ChipLogAutomation("HandleReadColorControlAttribute: Options: %d", color); // memcpy(buffer, &colorCapa, sizeof(colorCapa)); } else if((attributeId == ColorControl::Attributes::ColorTempPhysicalMinMireds::Id) && (maxReadLength == 2)) { // uint16_t min = 0x0000; // ChipLogAutomation("HandleReadColorControlAttribute: ColorTempPhysicalMinMireds: %d", min); // memcpy(buffer, &min, sizeof(min)); // } else if((attributeId == ColorControl::Attributes::ColorTempPhysicalMaxMireds::Id) && (maxReadLength == 2)) { // uint16_t min = 0xFEFF; // ChipLogAutomation("HandleReadColorControlAttribute: ColorTempPhysicalMaxMireds: %d", min); // memcpy(buffer, &min, sizeof(min)); } else if((attributeId == ColorControl::Attributes::Options::Id) && (maxReadLength == 1)) { // uint8_t options = 0x00; // ChipLogAutomation("HandleReadColorControlAttribute: Options: %d", options); // memcpy(buffer, &options, sizeof(options)); } else if((attributeId == ColorControl::Attributes::NumberOfPrimaries::Id) && (maxReadLength==1)){ // uint8_t num = 0x00; // ChipLogAutomation("HandleReadColorControlAttribute: NumberOfPrimaries: %d", num); // memcpy(buffer, &num, sizeof(num)); } else { return Protocols::InteractionModel::Status::Failure; } } Protocols::InteractionModel::Status HandleReadLevelControlAttribute(DeviceLevelControl * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) { ChipLogProgress(DeviceLayer, "HandleReadLevelControlAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); if ((attributeId == LevelControl::Attributes::CurrentLevel::Id) && (maxReadLength == 1)) { //ChipLogAutomation("HandleReadLevelControlAttribute: CurrentLevel: %d", dev->GetCurrentLevel()); //*buffer = 50; uint8_t Current = dev->GetCurrentLevel(); // if(Current <1 || Current > 254) // { // ChipLogAutomation("HandleReadLevelControlAttribute: CurrentLevel: %d", Current); // dev->SetCurrentLevel(1); // Current = dev->GetCurrentLevel(); // } memcpy(buffer, &Current, sizeof(Current)); ChipLogAutomation("HandleReadLevelControlAttribute: CurrentLevel: %d", buffer[0]); } else if ((attributeId == LevelControl::Attributes::RemainingTime::Id) && (maxReadLength == 2)) { uint16_t time = 0; memcpy(buffer, &time, sizeof(time)); ChipLogAutomation("HandleReadLevelControlAttribute: RemainingTime: %d", buffer[0]); } else if ((attributeId == LevelControl::Attributes::CurrentFrequency::Id) && (maxReadLength == 2)) { uint16_t frequency = 0; memcpy(buffer, &frequency, sizeof(frequency)); ChipLogAutomation("HandleReadLevelControlAttribute: CurrentFrequency: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::MinFrequency::Id) && (maxReadLength == 2)){ uint16_t min = 0; memcpy(buffer, &min, sizeof(min)); ChipLogAutomation("HandleReadLevelControlAttribute: MinFrequency: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::MaxFrequency::Id) && (maxReadLength == 2)){ uint16_t max = 0; memcpy(buffer, &max, sizeof(max)); ChipLogAutomation("HandleReadLevelControlAttribute: MaxFrequency: %d", buffer[0]); } else if ((attributeId == LevelControl::Attributes::MinLevel::Id) && (maxReadLength == 1)) { uint8_t min = 0x01; memcpy(buffer, &min, sizeof(min)); ChipLogAutomation("HandleReadLevelControlAttribute: MinLevel: %d", buffer[0]); } else if ((attributeId == LevelControl::Attributes::MaxLevel::Id) && (maxReadLength == 1)) { uint8_t max = 0xFE; memcpy(buffer, &max, sizeof(max)); ChipLogAutomation("HandleReadLevelControlAttribute: MaxLevel: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::Options::Id) && (maxReadLength == 1)) { uint8_t options = 0x00; memcpy(buffer, &options, sizeof(options)); ChipLogAutomation("HandleReadLevelControlAttribute: Options: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::OnOffTransitionTime::Id) && (maxReadLength == 2)){ uint16_t time = 0; memcpy(buffer, &time, sizeof(time)); ChipLogAutomation("HandleReadLevelControlAttribute: OnOffTransitionTime: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::OnTransitionTime::Id) && (maxReadLength == 16)){ uint16_t time = 0; memcpy(buffer, &time, sizeof(time)); ChipLogAutomation("HandleReadLevelControlAttribute: OnTransitionTime: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::OffTransitionTime::Id) && (maxReadLength == 16)){ uint16_t time = 0; memcpy(buffer, &time, sizeof(time)); ChipLogAutomation("HandleReadLevelControlAttribute: OffTransitionTime: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::DefaultMoveRate::Id) && (maxReadLength == 1)){ uint8_t rate = 50; memcpy(buffer, &rate, sizeof(rate)); ChipLogAutomation("HandleReadLevelControlAttribute: DefaultMoveRate: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::OnLevel::Id) && (maxReadLength == 1)){ uint8_t onlevel = 0xff; memcpy(buffer, &onlevel, sizeof(onlevel)); ChipLogAutomation("HandleReadLevelControlAttribute: OnLevel: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::StartUpCurrentLevel::Id) && (maxReadLength == 1)) { uint8_t startUp = 255; memcpy(buffer, &startUp, sizeof(startUp)); ChipLogAutomation("HandleReadLevelControlAttribute: StartUpCurrentLevel: %d", buffer[0]); } else if ((attributeId == LevelControl::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) { // uint16_t rev = ZCL_LEVEL_CONTROL_CLUSTER_REVISION; // memcpy(buffer, &rev, sizeof(rev)); } else if ((attributeId == LevelControl::Attributes::FeatureMap::Id) && (maxReadLength == 4)) { uint32_t featureMap = 0x03; ChipLogAutomation("HandleReadLevelControlAttribute: FeatureMap : %d", featureMap); memcpy(buffer, &featureMap, sizeof(featureMap)); } else if((attributeId == LevelControl::Attributes::Options::Id) && (maxReadLength == 1)) { uint8_t options = 0x00; memcpy(buffer, &options, sizeof(options)); ChipLogAutomation("HandleReadLevelControlAttribute: Options: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::StartUpCurrentLevel::Id) && (maxReadLength == 1)) { uint8_t startUp = 255; memcpy(buffer, &startUp, sizeof(startUp)); ChipLogAutomation("HandleReadLevelControlAttribute: StartUpCurrentLevel: %d", buffer[0]); } else if((attributeId == LevelControl::Attributes::DefaultMoveRate::Id) && (maxReadLength == 1)) { uint8_t startUp = 50; memcpy(buffer, &startUp, sizeof(startUp)); ChipLogAutomation("HandleReadLevelControlAttribute: StartUpOnOff: %d", buffer[0]); } else { return Protocols::InteractionModel::Status::Failure; } } Protocols::InteractionModel::Status HandleReadIdentityAttribute(Device * dev,chip::AttributeId attributeId, uint8_t * buffer ){ ChipLogProgress(DeviceLayer, "HandleReadIdentityAttribute: attrId=%d", attributeId); if(attributeId == Identify::Attributes::IdentifyTime::Id) { uint16_t time = 0; memcpy(buffer, &time, sizeof(time)); } else if(attributeId == Identify::Attributes::IdentifyType::Id) { uint8_t type = 0; memcpy(buffer, &type, sizeof(type)); } else if(attributeId == Identify::Attributes::FeatureMap::Id) { uint32_t rev = 0; memcpy(buffer, &rev, sizeof(rev)); } else if(attributeId == Identify::Attributes::ClusterRevision::Id) { uint16_t rev = 4; memcpy(buffer, &rev, sizeof(rev)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadGroupsAttribute(Device * dev,chip::AttributeId attributeId, uint8_t * buffer ){ ChipLogProgress(DeviceLayer, "HandleReadGroupsAttribute: attrId=%d", attributeId); if(attributeId == Groups::Attributes::NameSupport::Id) { uint8_t support = 0; memcpy(buffer, &support, sizeof(support)); } else if(attributeId == Groups::Attributes::FeatureMap::Id) { uint32_t rev = 0; memcpy(buffer, &rev, sizeof(rev)); } else if(attributeId == Groups::Attributes::ClusterRevision::Id) { uint16_t rev = 4; memcpy(buffer, &rev, sizeof(rev)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadScenesManagerAttribute(Device * dev,chip::AttributeId attributeId, uint8_t * buffer ){ ChipLogProgress(DeviceLayer, "HandleReadScenesManagerAttribute: attrId=%d", attributeId); if(attributeId == ScenesManagement::Attributes::LastConfiguredBy::Id) { uint8_t count = 0; memcpy(buffer, &count, sizeof(count)); } else if(attributeId == ScenesManagement::Attributes::SceneTableSize::Id) { uint16_t scene = 16; memcpy(buffer, &scene, sizeof(scene)); } else if(attributeId == ScenesManagement::Attributes::FabricSceneInfo::Id) { uint16_t group = 0; memcpy(buffer, &group, sizeof(group)); } else if (attributeId == ScenesManagement::Attributes::FeatureMap::Id) { uint32_t rev = 1; memcpy(buffer, &rev, sizeof(rev)); } else if(attributeId == ScenesManagement::Attributes::ClusterRevision::Id) { uint16_t rev = 1; memcpy(buffer, &rev, sizeof(rev)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleWriteOnOffAttribute(DeviceOnOff * dev, chip::AttributeId attributeId, uint8_t * buffer) { ChipLogProgress(DeviceLayer, "HandleWriteOnOffAttribute: attrId=%d", attributeId); if ((attributeId == OnOff::Attributes::OnOff::Id) && (dev->IsReachable())) { if (*buffer) { dev->SetOnOff(true); } else { dev->SetOnOff(false); } } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleWriteWindowCoveringAttribute(DeviceWindowCovering * dev, chip::AttributeId attributeId, uint8_t * buffer) { ChipLogProgress(DeviceLayer, "HandleWriteWindowCoveringAttribute: attrId=%d", attributeId); for(int i=0; i< sizeof(buffer); i++) { ChipLogProgress(DeviceLayer, "HandleWriteWindowCoveringAttribute: buffer[%d]=%d", i, buffer[i]); } if ((attributeId == WindowCovering::Attributes::TargetPositionLiftPercent100ths::Id) && (dev->IsReachable())) { uint16_t target = buffer[1] << 8 | buffer[0]; ChipLogAutomation("HandleWriteWindowCoveringAttribute: TargetPositionLiftPercent100ths: %d", target); dev->SetTargetPositionLiftPercentage(target); dev->SetCurrentPositionLiftPercentage(target); //OperationalStateSet(dev->GetEndpointId(), OperationalStatus::kLift, OperationalState::MovingDownOrClose); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleWriteColorControlAttribute(DeviceColorControl * dev, chip::AttributeId attributeId, uint8_t * buffer){ ChipLogProgress(DeviceLayer, "HandleWriteWindowCoveringAttribute: attrId=%d", attributeId); for(int i=0; i< sizeof(buffer); i++) { ChipLogProgress(DeviceLayer, "HandleWriteWindowCoveringAttribute: buffer[%d]=%d", i, buffer[i]); } if ((attributeId == ColorControl::Attributes::CurrentHue::Id) && (dev->IsReachable())) { uint8_t hue = buffer[0]; ChipLogAutomation("HandleWriteColorControlAttribute: CurrentHue: %d", hue); dev->SetCurrentHue(hue); }else if((attributeId == ColorControl::Attributes::CurrentSaturation::Id) && (dev->IsReachable())) { uint8_t saturation = buffer[0]; ChipLogAutomation("HandleWriteColorControlAttribute: CurrentSaturation: %d", saturation); dev->SetCurrentSaturation(saturation); }else if((attributeId == ColorControl::Attributes::ColorTemperatureMireds::Id) && (dev->IsReachable())) { uint8_t temperature = buffer[1] << 8 | buffer[0]; ChipLogAutomation("HandleWriteColorControlAttribute: ColorTemperatureMireds: %d", temperature); dev->SetCurrentTemperature(temperature); } } Protocols::InteractionModel::Status HandleWriteLevelControlAttribute(DeviceLevelControl * dev, chip::AttributeId attributeId, uint8_t * buffer){ ChipLogProgress(DeviceLayer, "HandleWriteLevelControlAttribute: attrId=%d", attributeId); for(int i=0; i< sizeof(buffer); i++) { ChipLogProgress(DeviceLayer, "HandleWriteLevelControlAttribute: buffer[%d]=%d", i, buffer[i]); } if ((attributeId == LevelControl::Attributes::CurrentLevel::Id) && (dev->IsReachable())) { dev->SetCurrentLevel(buffer[0]); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status HandleReadTempMeasurementAttribute(DeviceTempSensor * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) { using namespace TemperatureMeasurement::Attributes; if ((attributeId == MeasuredValue::Id) && (maxReadLength == 2)) { int16_t measuredValue = dev->GetMeasuredValue(); memcpy(buffer, &measuredValue, sizeof(measuredValue)); } else if ((attributeId == MinMeasuredValue::Id) && (maxReadLength == 2)) { int16_t minValue = dev->mMin; memcpy(buffer, &minValue, sizeof(minValue)); } else if ((attributeId == MaxMeasuredValue::Id) && (maxReadLength == 2)) { int16_t maxValue = dev->mMax; memcpy(buffer, &maxValue, sizeof(maxValue)); } else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4)) { uint32_t featureMap = ZCL_TEMPERATURE_SENSOR_FEATURE_MAP; memcpy(buffer, &featureMap, sizeof(featureMap)); } else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2)) { uint16_t clusterRevision = ZCL_TEMPERATURE_SENSOR_CLUSTER_REVISION; memcpy(buffer, &clusterRevision, sizeof(clusterRevision)); } else { return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Success; } Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) { uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure; if ((endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) && (gDevices[endpointIndex] != nullptr)) { Device * dev = gDevices[endpointIndex]; if (clusterId == BridgedDeviceBasicInformation::Id) { ret = HandleReadBridgedDeviceBasicAttribute(dev, attributeMetadata->attributeId, buffer, maxReadLength); } else if (clusterId == OnOff::Id) { ret = HandleReadOnOffAttribute(static_cast(dev), attributeMetadata->attributeId, buffer, maxReadLength); } else if (clusterId == TemperatureMeasurement::Id) { ret = HandleReadTempMeasurementAttribute(static_cast(dev), attributeMetadata->attributeId, buffer, maxReadLength); }else if (clusterId == WindowCovering::Id) { ret = HandleReadWindowCoveringAttribute(static_cast(dev), attributeMetadata->attributeId, buffer, maxReadLength); }else if (clusterId == ColorControl::Id) { ret = HandleReadColorControlAttribute(static_cast(dev), attributeMetadata->attributeId, buffer, maxReadLength); }else if (clusterId == LevelControl::Id) { ret = HandleReadLevelControlAttribute(static_cast(dev), attributeMetadata->attributeId, buffer, maxReadLength); } else if (clusterId == Identify::Id){ ret = HandleReadIdentityAttribute(dev, attributeMetadata->attributeId, buffer); } else if (clusterId == Groups::Id){ ret = HandleReadGroupsAttribute(dev, attributeMetadata->attributeId, buffer); } else if (clusterId == ScenesManagement::Id){ ret = HandleReadScenesManagerAttribute(dev, attributeMetadata->attributeId, buffer); } } return ret; } class BridgedPowerSourceAttrAccess : public AttributeAccessInterface { public: // Register on all endpoints. BridgedPowerSourceAttrAccess() : AttributeAccessInterface(Optional::Missing(), PowerSource::Id) {} CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override { uint16_t powerSourceDeviceIndex = CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; if ((gDevices[powerSourceDeviceIndex] != nullptr)) { DevicePowerSource * dev = static_cast(gDevices[powerSourceDeviceIndex]); if (aPath.mEndpointId != dev->GetEndpointId()) { return CHIP_IM_GLOBAL_STATUS(UnsupportedEndpoint); } switch (aPath.mAttributeId) { case PowerSource::Attributes::BatChargeLevel::Id: aEncoder.Encode(dev->GetBatChargeLevel()); break; case PowerSource::Attributes::Order::Id: aEncoder.Encode(dev->GetOrder()); break; case PowerSource::Attributes::Status::Id: aEncoder.Encode(dev->GetStatus()); break; case PowerSource::Attributes::Description::Id: aEncoder.Encode(chip::CharSpan(dev->GetDescription().c_str(), dev->GetDescription().size())); break; case PowerSource::Attributes::EndpointList::Id: { std::vector & list = dev->GetEndpointList(); DataModel::List dm_list(chip::Span(list.data(), list.size())); aEncoder.Encode(dm_list); break; } case PowerSource::Attributes::ClusterRevision::Id: aEncoder.Encode(ZCL_POWER_SOURCE_CLUSTER_REVISION); break; case PowerSource::Attributes::FeatureMap::Id: aEncoder.Encode(dev->GetFeatureMap()); break; case PowerSource::Attributes::BatReplacementNeeded::Id: aEncoder.Encode(false); break; case PowerSource::Attributes::BatReplaceability::Id: aEncoder.Encode(PowerSource::BatReplaceabilityEnum::kNotReplaceable); break; default: return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); } } return CHIP_NO_ERROR; } }; BridgedPowerSourceAttrAccess gPowerAttrAccess; Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer) { uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure; // ChipLogProgress(DeviceLayer, "emberAfExternalAttributeWriteCallback: ep=%d", endpoint); if (endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) { Device * dev = gDevices[endpointIndex]; if ((dev->IsReachable()) && (clusterId == OnOff::Id)) { ret = HandleWriteOnOffAttribute(static_cast(dev), attributeMetadata->attributeId, buffer); }else if((dev->IsReachable()) && (clusterId == WindowCovering::Id)) { ret = HandleWriteWindowCoveringAttribute(static_cast(dev), attributeMetadata->attributeId, buffer); }else if ((dev->IsReachable()) && (clusterId == ColorControl::Id)) { ret = HandleWriteColorControlAttribute(static_cast(dev), attributeMetadata->attributeId, buffer); } else if ((dev->IsReachable()) && (clusterId == LevelControl::Id)) { ret = HandleWriteLevelControlAttribute(static_cast(dev), attributeMetadata->attributeId, buffer); } } return ret; } void runOnOffRoomAction(Room * room, bool actionOn, EndpointId endpointId, uint16_t actionID, uint32_t invokeID, bool hasInvokeID) { if (hasInvokeID) { Actions::Events::StateChanged::Type event{ actionID, invokeID, Actions::ActionStateEnum::kActive }; EventNumber eventNumber; chip::app::LogEvent(event, endpointId, eventNumber); } // Check and run the action for ActionLight1 - ActionLight4 if (room->getName().compare(ActionLight1.GetLocation()) == 0) { ActionLight1.SetOnOff(actionOn); } if (room->getName().compare(ActionLight2.GetLocation()) == 0) { ActionLight2.SetOnOff(actionOn); } if (room->getName().compare(ActionLight3.GetLocation()) == 0) { ActionLight3.SetOnOff(actionOn); } if (room->getName().compare(ActionLight4.GetLocation()) == 0) { ActionLight4.SetOnOff(actionOn); } if (hasInvokeID) { Actions::Events::StateChanged::Type event{ actionID, invokeID, Actions::ActionStateEnum::kInactive }; EventNumber eventNumber; chip::app::LogEvent(event, endpointId, eventNumber); } } bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, const Actions::Commands::InstantAction::DecodableType & commandData) { bool hasInvokeID = false; uint32_t invokeID = 0; EndpointId endpointID = commandPath.mEndpointId; auto & actionID = commandData.actionID; if (commandData.invokeID.HasValue()) { hasInvokeID = true; invokeID = commandData.invokeID.Value(); } if (actionID == action1.getActionId() && action1.getIsVisible()) { // Turn On Lights in Room 1 runOnOffRoomAction(&room1, true, endpointID, actionID, invokeID, hasInvokeID); commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); return true; } if (actionID == action2.getActionId() && action2.getIsVisible()) { // Turn On Lights in Room 2 runOnOffRoomAction(&room2, true, endpointID, actionID, invokeID, hasInvokeID); commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); return true; } if (actionID == action3.getActionId() && action3.getIsVisible()) { // Turn Off Lights in Room 1 runOnOffRoomAction(&room1, false, endpointID, actionID, invokeID, hasInvokeID); commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); return true; } commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); return true; } const EmberAfDeviceType gBridgedOnOffDeviceTypes[] = { { DEVICE_TYPE_LO_ON_OFF_LIGHT, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gColorExtendDeviceTypes[] = { { DEVICE_TYPE_COLOR_EXTEND_LIGHT, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT} }; const EmberAfDeviceType gBridgedComposedDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_POWER_SOURCE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gComposedTempSensorDeviceTypes[] = { { DEVICE_TYPE_TEMP_SENSOR, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gBridgedTempSensorDeviceTypes[] = { { DEVICE_TYPE_TEMP_SENSOR, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gBridgedWindowCoveringDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_WINDOW_COVERING, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gBridgedLevelControlDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_LEVEL_CONTROL, DEVICE_VERSION_DEFAULT } }; #define POLL_INTERVAL_MS (100) uint8_t poll_prescale = 0; bool kbhit() { int byteswaiting; ioctl(0, FIONREAD, &byteswaiting); return byteswaiting > 0; } const int16_t oneDegree = 100; void * bridge_polling_thread(void * context) { bool light1_added = true; bool light2_added = false; while (true) { if (kbhit()) { int ch = getchar(); // Commands used for the actions bridge test plan. if (ch == '2' && light2_added == false) { // TC-BR-2 step 2, Add Light2 AddDeviceEndpoint(&Light2, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), Span(gLight2DataVersions), 1); light2_added = true; } else if (ch == '4' && light1_added == true) { // TC-BR-2 step 4, Remove Light 1 RemoveDeviceEndpoint(&Light1); light1_added = false; } if (ch == '5' && light1_added == false) { // TC-BR-2 step 5, Add Light 1 back AddDeviceEndpoint(&Light1, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), Span(gLight1DataVersions), 1); light1_added = true; } if (ch == 'b') { // TC-BR-3 step 1b, rename lights if (light1_added) { Light1.SetName("Light 1b"); } if (light2_added) { Light2.SetName("Light 2b"); } } if (ch == 'c') { // TC-BR-3 step 2c, change the state of the lights if (light1_added) { Light1.Toggle(); } if (light2_added) { Light2.Toggle(); } } if (ch == 't') { // TC-BR-4 step 1g, change the state of the temperature sensors TempSensor1.SetMeasuredValue(static_cast(TempSensor1.GetMeasuredValue() + oneDegree)); TempSensor2.SetMeasuredValue(static_cast(TempSensor2.GetMeasuredValue() + oneDegree)); ComposedTempSensor1.SetMeasuredValue(static_cast(ComposedTempSensor1.GetMeasuredValue() + oneDegree)); ComposedTempSensor2.SetMeasuredValue(static_cast(ComposedTempSensor2.GetMeasuredValue() + oneDegree)); } // Commands used for the actions cluster test plan. if (ch == 'r') { // TC-ACT-2.2 step 2c, rename "Room 1" room1.setName("Room 1 renamed"); ActionLight1.SetLocation(room1.getName()); ActionLight2.SetLocation(room1.getName()); } if (ch == 'f') { // TC-ACT-2.2 step 2f, move "Action Light 3" from "Room 2" to "Room 1" ActionLight3.SetLocation(room1.getName()); } if (ch == 'i') { // TC-ACT-2.2 step 2i, remove "Room 2" (make it not visible in the endpoint list), do not remove the lights room2.setIsVisible(false); } if (ch == 'l') { // TC-ACT-2.2 step 2l, add a new "Zone 3" and add "Action Light 2" to the new zone room3.setIsVisible(true); ActionLight2.SetZone("Zone 3"); } if (ch == 'm') { // TC-ACT-2.2 step 3c, rename "Turn on Room 1 lights" action1.setName("Turn On Room 1"); } if (ch == 'n') { // TC-ACT-2.2 step 3f, remove "Turn on Room 2 lights" action2.setIsVisible(false); } if (ch == 'o') { // TC-ACT-2.2 step 3i, add "Turn off Room 1 renamed lights" action3.setIsVisible(true); } // Commands used for the Bridged Device Basic Information test plan if (ch == 'u') { // TC-BRBINFO-2.2 step 2 "Set reachable to false" TempSensor1.SetReachable(false); } if (ch == 'v') { // TC-BRBINFO-2.2 step 2 "Set reachable to true" TempSensor1.SetReachable(true); } continue; } // Sleep to avoid tight loop reading commands usleep(POLL_INTERVAL_MS * 1000); } return nullptr; } void ApplicationInit() { // Clear out the device database memset(gDevices, 0, sizeof(gDevices)); // Setup Mock Devices Light1.SetReachable(true); // Light2.SetReachable(true); WindowCovering1.SetReachable(true); ColorExtend1.SetReachable(true); LevelControl1.SetReachable(true); LevelControl1.SetChangeCallback(&HandleDeviceLevelControlStatusChanged); WindowCovering1.SetChangeCallback(&HandleDeviceWindowCoveringStatusChanged); ColorExtend1.SetChangeCallback(&HandleDeviceColorExtendStatusChanged); Light1.SetChangeCallback(&HandleDeviceOnOffStatusChanged); // Light2.SetChangeCallback(&HandleDeviceOnOffStatusChanged); TempSensor1.SetReachable(true); TempSensor1.SetReachable(true); TempSensor1.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); TempSensor2.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); // Setup devices for action cluster tests // ActionLight1.SetReachable(true); // ActionLight2.SetReachable(true); // ActionLight3.SetReachable(true); // ActionLight4.SetReachable(true); // ActionLight1.SetChangeCallback(&HandleDeviceOnOffStatusChanged); // ActionLight2.SetChangeCallback(&HandleDeviceOnOffStatusChanged); // ActionLight3.SetChangeCallback(&HandleDeviceOnOffStatusChanged); // ActionLight4.SetChangeCallback(&HandleDeviceOnOffStatusChanged); // Setup composed device with two temperature sensors and a power source // ComposedDevice ComposedDevice("Composed Device", "Bedroom"); // DevicePowerSource ComposedPowerSource("Composed Power Source", "Bedroom", PowerSource::Feature::kBattery); // ComposedDevice.SetReachable(true); // ComposedTempSensor1.SetReachable(true); // ComposedTempSensor2.SetReachable(true); // ComposedPowerSource.SetReachable(true); // ComposedPowerSource.SetBatChargeLevel(58); // ComposedTempSensor1.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); // ComposedTempSensor2.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); // ComposedPowerSource.SetChangeCallback(&HandleDevicePowerSourceStatusChanged); // Set starting endpoint id where dynamic endpoints will be assigned, which // will be the next consecutive endpoint id after the last fixed endpoint. gFirstDynamicEndpointId = static_cast( static_cast(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1))) + 1); gCurrentEndpointId = gFirstDynamicEndpointId; // Disable last fixed endpoint, which is used as a placeholder for all of the // supported clusters so that ZAP will generated the requisite code. emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1)), false); // // Add light 1 -> will be mapped to ZCL endpoints 3 // AddDeviceEndpoint(&Light1, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), //Span(gLight1DataVersions), 1); // // Add Temperature Sensor devices --> will be mapped to endpoints 4,5 // AddDeviceEndpoint(&TempSensor1, &bridgedTempSensorEndpoint, Span(gBridgedTempSensorDeviceTypes), // Span(gTempSensor1DataVersions), 1); // AddDeviceEndpoint(&TempSensor2, &bridgedTempSensorEndpoint, Span(gBridgedTempSensorDeviceTypes), // Span(gTempSensor2DataVersions), 1); // // Add composed Device with two temperature sensors and a power source // AddDeviceEndpoint(&ComposedDevice, &bridgedComposedDeviceEndpoint, Span(gBridgedComposedDeviceTypes), // Span(gComposedDeviceDataVersions), 1); // AddDeviceEndpoint(&ComposedTempSensor1, &bridgedTempSensorEndpoint, // Span(gComposedTempSensorDeviceTypes), // Span(gComposedTempSensor1DataVersions), ComposedDevice.GetEndpointId()); // AddDeviceEndpoint(&ComposedTempSensor2, &bridgedTempSensorEndpoint, // Span(gComposedTempSensorDeviceTypes), // Span(gComposedTempSensor2DataVersions), ComposedDevice.GetEndpointId()); // // Add 4 lights for the Action Clusters tests // AddDeviceEndpoint(&ActionLight1, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), // Span(gActionLight1DataVersions), 1); // AddDeviceEndpoint(&ActionLight2, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), // Span(gActionLight2DataVersions), 1); // AddDeviceEndpoint(&ActionLight3, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), // Span(gActionLight3DataVersions), 1); // AddDeviceEndpoint(&ActionLight4, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), // Span(gActionLight4DataVersions), 1); //AddDeviceEndpoint(&WindowCovering1, &bridgedWindowCoveringEndpoint,Span(gBridgedWindowCoveringDeviceTypes), //Span(gWindowCoveringDataVersions),1); AddDeviceEndpoint(&ColorExtend1, &bridgedColorExtendEndpoint,Span(gColorExtendDeviceTypes), Span(gColorExtendDataVersions),1); //AddDeviceEndpoint(&LevelControl1, &bridgedLevelControlEndpoint,Span(gBridgedLevelControlDeviceTypes), // Span(gLevelControlDataVersions),1); // Because the power source is on the same endpoint as the composed device, it needs to be explicitly added // gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT] = &ComposedPowerSource; // // This provides power for the composed endpoint // std::vector endpointList; // endpointList.push_back(ComposedDevice.GetEndpointId()); // endpointList.push_back(ComposedTempSensor1.GetEndpointId()); // endpointList.push_back(ComposedTempSensor2.GetEndpointId()); // ComposedPowerSource.SetEndpointList(endpointList); // ComposedPowerSource.SetEndpointId(ComposedDevice.GetEndpointId()); // gRooms.push_back(&room1); // gRooms.push_back(&room2); // gRooms.push_back(&room3); // gActions.push_back(&action1); // gActions.push_back(&action2); // gActions.push_back(&action3); { pthread_t poll_thread; int res = pthread_create(&poll_thread, nullptr, bridge_polling_thread, nullptr); if (res) { printf("Error creating polling thread: %d\n", res); exit(1); } } registerAttributeAccessOverride(&gPowerAttrAccess); } void ApplicationShutdown() {} int main(int argc, char * argv[]) { if(!chip::Logging::Platform::InitLog("/tmp/log/bridge_matter.log")) { fprintf(stderr, "Failed to initialize logging\n"); return -1; } if (ChipLinuxAppInit(argc, argv) != 0) { return -1; } ChipLinuxAppMainLoop(); return 0; }