diff --git a/src/app/clusters/network-commissioning/network-commissioning.cpp b/src/app/clusters/network-commissioning/network-commissioning.cpp index 6bb3356b89..f208a0024a 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.cpp +++ b/src/app/clusters/network-commissioning/network-commissioning.cpp @@ -680,17 +680,70 @@ void Instance::OnNetworkingStatusChange(Status aCommissioningError, OptionalGetConnectNetworkTimeoutSeconds() : 20; + DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(timeoutSec), DeferredErrorTimerFiredStatic, this); + } + } +#endif +} + +#if !CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + +void Instance::ResetSuccessTimestamp() +{ + mLastSuccessTimestamp = System::Clock::kZero; +} + +void Instance::DeferredErrorTimerFiredStatic(System::Layer *, void * context) +{ + static_cast(context)->DeferredErrorTimerFired(); +} + +void Instance::DeferredErrorTimerFired() +{ + if (mDeferredErrorPending) + { + mDeferredErrorPending = false; + SetLastNetworkingStatusValue(mDeferredLastStatus); + SetLastConnectErrorValue(mDeferredConnectError.HasValue() ? MakeNullable(mDeferredConnectError.Value()) : NullNullable); } } +void Instance::CancelPendingError() +{ + if (mDeferredErrorPending) + { + DeviceLayer::SystemLayer().CancelTimer(DeferredErrorTimerFiredStatic, this); + mDeferredErrorPending = false; + } +} +#endif + void Instance::HandleScanNetworks(HandlerContext & ctx, const Commands::ScanNetworks::DecodableType & req) { MATTER_TRACE_SCOPE("HandleScanNetwork", "NetworkCommissioning"); @@ -1046,6 +1099,10 @@ void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::Connec mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler); mCurrentOperationBreadcrumb = req.breadcrumb; +#if !CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + ResetSuccessTimestamp(); +#endif + #if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION // Per spec, lingering connections on any other interfaces need to be disconnected at this point. for (auto & node : sInstances) diff --git a/src/app/clusters/network-commissioning/network-commissioning.h b/src/app/clusters/network-commissioning/network-commissioning.h index d727c9b6c2..10657dde24 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.h +++ b/src/app/clusters/network-commissioning/network-commissioning.h @@ -126,11 +126,25 @@ class Instance : public CommandHandlerInterface, Optional mCurrentOperationBreadcrumb; bool mScanningWasDirected = false; +#if !CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + System::Clock::Timestamp mLastSuccessTimestamp{}; + bool mDeferredErrorPending = false; + DeviceLayer::NetworkCommissioning::Status mDeferredLastStatus; + Optional mDeferredConnectError; +#endif + void SetLastNetworkingStatusValue(Attributes::LastNetworkingStatus::TypeInfo::Type networkingStatusValue); void SetLastConnectErrorValue(Attributes::LastConnectErrorValue::TypeInfo::Type connectErrorValue); void SetLastNetworkId(ByteSpan lastNetworkId); void ReportNetworksListChanged() const; +#if !CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + void ResetSuccessTimestamp(); + static void DeferredErrorTimerFiredStatic(System::Layer *, void * context); + void DeferredErrorTimerFired(); + void CancelPendingError(); +#endif + #if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION // Disconnect if the current connection is not in the Networks list void DisconnectLingeringConnection(); diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 2ef6a7551d..1c7cfc416a 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1467,6 +1467,24 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE 64 #endif // CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE +/* + * @def CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + * + * @brief If enabled, networking status and connection error values (LastNetworkingStatus / LastConnectErrorValue) + * are updated immediately upon receiving the result from the driver. + * + * If disabled, errors will be reported only after the driver-defined connect timeout (e.g. 30s), + * to avoid reflecting transient failures too early. + * + * This allows delaying status reporting to reduce the impact of temporary network instabilities. + * + * Default: 1 (enabled) + */ +#ifndef CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING +#define CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING 0 +#endif // CHIP_CONFIG_NETWORK_COMMISSIONING_IMMEDIATE_STATUS_REPORTING + + /** * @def CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT *