blob: 85295328bc40a5e0d5250bb17b21276203ee8ecf [file] [log] [blame]
package com.matter.controller.commands.pairing
import com.matter.controller.commands.common.CredentialsIssuer
import java.util.logging.Level
import java.util.logging.Logger
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.runBlocking
import matter.controller.MatterController
import matter.controller.SubscribeRequest
import matter.controller.SubscriptionState
import matter.controller.UShortSubscriptionState
import matter.controller.cluster.clusters.IdentifyCluster
import matter.controller.model.AttributePath
import matter.controller.model.EventPath
class PairOnNetworkLongImSubscribeCommand(
controller: MatterController,
credsIssue: CredentialsIssuer?
) :
PairingCommand(
controller,
"onnetwork-long-im-subscribe",
credsIssue,
PairingModeType.ON_NETWORK,
PairingNetworkType.NONE,
DiscoveryFilterType.LONG_DISCRIMINATOR
) {
override fun runCommand() {
currentCommissioner()
.pairDevice(
getNodeId(),
getRemoteAddr().address.hostAddress,
MATTER_PORT,
getDiscriminator(),
getSetupPINCode(),
)
currentCommissioner().setCompletionListener(this)
waitCompleteMs(getTimeoutMillis())
runBlocking {
try {
// Verify Wildcard subscription
startWildcardSubscription()
// Verify IdentifyTime attribute subscription
subscribeIdentifyTimeAttribute()
} catch (ex: Exception) {
logger.log(Level.WARNING, "General subscribe failure occurred with error ${ex.message}")
setFailure("subscribe failure")
} finally {
clear()
}
}
setSuccess()
}
private suspend fun startWildcardSubscription() {
logger.log(Level.INFO, "Starting wildcard subscription")
val attributePaths =
listOf(
AttributePath(
endpointId = WILDCARD_ENDPOINT_ID,
clusterId = WILDCARD_CLUSTER_ID,
attributeId = WILDCARD_EVENT_ID,
)
)
val eventPaths =
listOf(
EventPath(
endpointId = WILDCARD_ENDPOINT_ID,
clusterId = WILDCARD_CLUSTER_ID,
eventId = WILDCARD_EVENT_ID
)
)
val request: SubscribeRequest = SubscribeRequest(eventPaths, attributePaths)
currentCommissioner()
.subscribe(request)
.takeWhile { subscriptionState ->
// Keep collecting as long as it's not SubscriptionEstablished
subscriptionState !is SubscriptionState.SubscriptionEstablished
}
.collect { subscriptionState ->
when (subscriptionState) {
is SubscriptionState.NodeStateUpdate -> {
logger.log(Level.INFO, "Received NodeStateUpdate: ${subscriptionState.updateState}")
// TODO: Add more validation rules as needed
}
is SubscriptionState.SubscriptionErrorNotification -> {
logger.log(
Level.WARNING,
"Received SubscriptionErrorNotification with terminationCause: ${subscriptionState.terminationCause}"
)
}
is SubscriptionState.SubscriptionEstablished -> {
logger.log(Level.INFO, "Wildcard Subscription is established")
}
else -> {
logger.log(Level.SEVERE, "Unexpected subscription state: $subscriptionState")
}
}
}
}
private suspend fun subscribeIdentifyTimeAttribute() {
logger.log(Level.INFO, "Subscribe IdentifyTime attribute")
val identifyCluster = IdentifyCluster(controller = currentCommissioner(), endpointId = 0u)
identifyCluster
.subscribeIdentifyTimeAttribute(minInterval = 0, maxInterval = 5)
.takeWhile { subscriptionState ->
// Keep collecting as long as it's not SubscriptionEstablished
subscriptionState !is UShortSubscriptionState.SubscriptionEstablished
}
.collect { subscriptionState ->
when (subscriptionState) {
is UShortSubscriptionState.Success -> {
logger.log(Level.INFO, "Received IdentifyTime Update: ${subscriptionState.value}")
}
is UShortSubscriptionState.Error -> {
logger.log(
Level.WARNING,
"Received SubscriptionErrorNotification with terminationCause: ${subscriptionState.exception}"
)
}
is UShortSubscriptionState.SubscriptionEstablished -> {
logger.log(Level.INFO, "IdentifyTime Subscription is established")
}
else -> {
logger.log(Level.SEVERE, "Unexpected subscription state: $subscriptionState")
}
}
}
}
companion object {
private val logger = Logger.getLogger(PairOnNetworkLongImSubscribeCommand::class.java.name)
private const val MATTER_PORT = 5540
private const val WILDCARD_ENDPOINT_ID: UShort = 0xffffu
private const val WILDCARD_CLUSTER_ID: UInt = 0xffffffffu
private const val WILDCARD_ATTRIBUTE_ID: UInt = 0xffffffffu
private const val WILDCARD_EVENT_ID: UInt = 0xffffffffu
}
}