| /* |
| * 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 "FabricBridge.h" |
| |
| #include <fabric-bridge-common/BridgedDevice.h> |
| #include <fabric-bridge-common/BridgedDeviceManager.h> |
| |
| #include <app/clusters/ecosystem-information-server/ecosystem-information-server.h> |
| #include <lib/core/CHIPError.h> |
| |
| #include <string> |
| |
| using namespace chip; |
| |
| namespace bridge { |
| |
| FabricBridge FabricBridge::sInstance; |
| |
| FabricBridge & FabricBridge::Instance() |
| { |
| return sInstance; |
| } |
| |
| CHIP_ERROR FabricBridge::AddSynchronizedDevice(const SynchronizedDevice & data) |
| { |
| ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: Id=[%d:" ChipLogFormatX64 "]", data.id.GetFabricIndex(), |
| ChipLogValueX64(data.id.GetNodeId())); |
| |
| // Create a new BridgedDevice and set it as reachable |
| auto device = std::make_unique<BridgedDevice>(data.id); |
| device->SetReachable(true); |
| |
| // Initialize BridgedDevice attributes from data |
| BridgedDevice::BridgedAttributes attributes; |
| |
| if (data.uniqueId.has_value()) |
| { |
| attributes.uniqueId = data.uniqueId.value(); |
| } |
| |
| if (data.vendorName.has_value()) |
| { |
| attributes.vendorName = data.vendorName.value(); |
| } |
| |
| if (data.vendorId.has_value()) |
| { |
| attributes.vendorId = data.vendorId.value(); |
| } |
| |
| if (data.productName.has_value()) |
| { |
| attributes.productName = data.productName.value(); |
| } |
| |
| if (data.productId.has_value()) |
| { |
| attributes.productId = data.productId.value(); |
| } |
| |
| if (data.nodeLabel.has_value()) |
| { |
| attributes.nodeLabel = data.nodeLabel.value(); |
| } |
| |
| if (data.hardwareVersion.has_value()) |
| { |
| attributes.hardwareVersion = data.hardwareVersion.value(); |
| } |
| |
| if (data.hardwareVersionString.has_value()) |
| { |
| attributes.hardwareVersionString = data.hardwareVersionString.value(); |
| } |
| |
| if (data.softwareVersion.has_value()) |
| { |
| attributes.softwareVersion = data.softwareVersion.value(); |
| } |
| |
| if (data.softwareVersionString.has_value()) |
| { |
| attributes.softwareVersionString = data.softwareVersionString.value(); |
| } |
| |
| // Set bridged device attributes and ICD status |
| device->SetBridgedAttributes(attributes); |
| device->SetIcd(data.isIcd.value_or(false)); |
| |
| // Add the device to the bridge manager with a parent endpoint |
| auto result = BridgedDeviceManager::Instance().AddDeviceEndpoint(std::move(device), /* parentEndpointId= */ 1); |
| if (!result.has_value()) |
| { |
| ChipLogError(NotSpecified, "Failed to add device with Id=[%d:0x" ChipLogFormatX64 "]", data.id.GetFabricIndex(), |
| ChipLogValueX64(data.id.GetNodeId())); |
| return CHIP_ERROR_ENDPOINT_POOL_FULL; |
| } |
| |
| // Retrieve and verify the added device by ScopedNodeId |
| BridgedDevice * addedDevice = BridgedDeviceManager::Instance().GetDeviceByScopedNodeId(data.id); |
| VerifyOrDie(addedDevice); |
| |
| ChipLogProgress(NotSpecified, "Added device with Id=[%d:0x" ChipLogFormatX64 "]", data.id.GetFabricIndex(), |
| ChipLogValueX64(data.id.GetNodeId())); |
| |
| // Add the Ecosystem Information Cluster to the device's endpoint |
| CHIP_ERROR err = |
| app::Clusters::EcosystemInformation::EcosystemInformationServer::Instance().AddEcosystemInformationClusterToEndpoint( |
| addedDevice->GetEndpointId()); |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(NotSpecified, "Failed to add Ecosystem Information Cluster to endpoint %u: %" CHIP_ERROR_FORMAT, |
| addedDevice->GetEndpointId(), err.Format()); |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR FabricBridge::RemoveSynchronizedDevice(ScopedNodeId scopedNodeId) |
| { |
| ChipLogProgress(NotSpecified, "Received RemoveSynchronizedDevice: Id=[%d:" ChipLogFormatX64 "]", scopedNodeId.GetFabricIndex(), |
| ChipLogValueX64(scopedNodeId.GetNodeId())); |
| |
| auto removedIdx = BridgedDeviceManager::Instance().RemoveDeviceByScopedNodeId(scopedNodeId); |
| if (!removedIdx.has_value()) |
| { |
| ChipLogError(NotSpecified, "Failed to remove device with Id=[%d:0x" ChipLogFormatX64 "]", scopedNodeId.GetFabricIndex(), |
| ChipLogValueX64(scopedNodeId.GetNodeId())); |
| return CHIP_ERROR_NOT_FOUND; |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR FabricBridge::ActiveChanged(ScopedNodeId scopedNodeId, uint32_t promisedActiveDurationMs) |
| { |
| ChipLogProgress(NotSpecified, "Received ActiveChanged: Id=[%d:" ChipLogFormatX64 "]", scopedNodeId.GetFabricIndex(), |
| ChipLogValueX64(scopedNodeId.GetNodeId())); |
| |
| auto * device = BridgedDeviceManager::Instance().GetDeviceByScopedNodeId(scopedNodeId); |
| if (device == nullptr) |
| { |
| ChipLogError(NotSpecified, "Could not find bridged device associated with Id=[%d:0x" ChipLogFormatX64 "]", |
| scopedNodeId.GetFabricIndex(), ChipLogValueX64(scopedNodeId.GetNodeId())); |
| return CHIP_ERROR_NOT_FOUND; |
| } |
| |
| device->LogActiveChangeEvent(promisedActiveDurationMs); |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR FabricBridge::AdminCommissioningAttributeChanged(const AdministratorCommissioningChanged & data) |
| { |
| ChipLogProgress(NotSpecified, "Received CADMIN attribute change: Id=[%d:" ChipLogFormatX64 "]", data.id.GetFabricIndex(), |
| ChipLogValueX64(data.id.GetNodeId())); |
| |
| auto * device = BridgedDeviceManager::Instance().GetDeviceByScopedNodeId(data.id); |
| if (device == nullptr) |
| { |
| ChipLogError(NotSpecified, "Could not find bridged device associated with Id=[%d:0x" ChipLogFormatX64 "]", |
| data.id.GetFabricIndex(), ChipLogValueX64(data.id.GetNodeId())); |
| return CHIP_ERROR_NOT_FOUND; |
| } |
| |
| BridgedDevice::AdminCommissioningAttributes adminCommissioningAttributes; |
| |
| VerifyOrReturnError(data.windowStatus < |
| app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kUnknownEnumValue, |
| CHIP_ERROR_INVALID_ARGUMENT); |
| |
| adminCommissioningAttributes.commissioningWindowStatus = data.windowStatus; |
| if (data.openerFabricIndex.has_value()) |
| { |
| VerifyOrReturnError(data.openerFabricIndex >= kMinValidFabricIndex, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(data.openerFabricIndex <= kMaxValidFabricIndex, CHIP_ERROR_INVALID_ARGUMENT); |
| adminCommissioningAttributes.openerFabricIndex = data.openerFabricIndex; |
| } |
| |
| if (data.openerVendorId.has_value()) |
| { |
| VerifyOrReturnError(data.openerVendorId != VendorId::NotSpecified, CHIP_ERROR_INVALID_ARGUMENT); |
| adminCommissioningAttributes.openerVendorId = data.openerVendorId; |
| } |
| |
| device->SetAdminCommissioningAttributes(adminCommissioningAttributes); |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR FabricBridge::DeviceReachableChanged(ScopedNodeId scopedNodeId, bool reachability) |
| { |
| ChipLogProgress(NotSpecified, "Received device reachable changed: Id=[%d:" ChipLogFormatX64 "]", scopedNodeId.GetFabricIndex(), |
| ChipLogValueX64(scopedNodeId.GetNodeId())); |
| |
| auto * device = BridgedDeviceManager::Instance().GetDeviceByScopedNodeId(scopedNodeId); |
| if (device == nullptr) |
| { |
| ChipLogError(NotSpecified, "Could not find bridged device associated with Id=[%d:0x" ChipLogFormatX64 "]", |
| scopedNodeId.GetFabricIndex(), ChipLogValueX64(scopedNodeId.GetNodeId())); |
| return CHIP_ERROR_NOT_FOUND; |
| } |
| |
| device->ReachableChanged(reachability); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| } // namespace bridge |