Skip to content

Commit

Permalink
[Kotlin] Implement Kotlin Cluster Library APIs (project-chip#30887)
Browse files Browse the repository at this point in the history
* Implement Kotlin cluster API

* Update examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt

Co-authored-by: Andrei Litvin <[email protected]>

* Address review comments

* Process using loops and keep track if we got data or not

---------

Co-authored-by: Andrei Litvin <[email protected]>
  • Loading branch information
yufengwangca and andy31415 authored Dec 11, 2023
1 parent 9fae101 commit 3f80447
Show file tree
Hide file tree
Showing 203 changed files with 79,842 additions and 13,833 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,11 @@
package com.matter.controller.commands.pairing

import com.matter.controller.commands.common.CredentialsIssuer
import java.time.Duration
import java.util.logging.Level
import java.util.logging.Logger
import kotlinx.coroutines.runBlocking
import matter.controller.InvokeRequest
import matter.controller.InvokeResponse
import matter.controller.MatterController
import matter.controller.model.CommandPath
import matter.tlv.AnonymousTag
import matter.tlv.ContextSpecificTag
import matter.tlv.TlvWriter
import matter.devicecontroller.cluster.clusters.IdentifyCluster

class PairOnNetworkLongImInvokeCommand(
controller: MatterController,
Expand All @@ -43,19 +37,6 @@ class PairOnNetworkLongImInvokeCommand(
DiscoveryFilterType.LONG_DISCRIMINATOR
) {
override fun runCommand() {
val IdentifyTime: UShort = 1u
val tlvWriter1 = TlvWriter()
tlvWriter1.startStructure(AnonymousTag)
tlvWriter1.put(ContextSpecificTag(0), IdentifyTime)
tlvWriter1.endStructure()

val element1: InvokeRequest =
InvokeRequest(
CommandPath(endpointId = 0u, clusterId = CLUSTER_ID_IDENTIFY, commandId = IDENTIFY_COMMAND),
tlvPayload = tlvWriter1.getEncoded(),
timedRequest = Duration.ZERO
)

currentCommissioner()
.pairDevice(
getNodeId(),
Expand All @@ -69,11 +50,10 @@ class PairOnNetworkLongImInvokeCommand(

runBlocking {
try {
val response: InvokeResponse = currentCommissioner().invoke(element1)
val identifyTime: UShort = 1u
val identifyCluster = IdentifyCluster(controller = currentCommissioner(), endpointId = 0u)
identifyCluster.identify(identifyTime)
logger.log(Level.INFO, "Invoke command succeeded")
if (response.payload.isNotEmpty()) {
// TODO:Handle TLV data response
}
} catch (ex: Exception) {
setFailure("invoke failure: ${ex.message}")
} finally {
Expand All @@ -86,11 +66,6 @@ class PairOnNetworkLongImInvokeCommand(

companion object {
private val logger = Logger.getLogger(PairOnNetworkLongImInvokeCommand::class.java.name)

private const val MATTER_PORT = 5540
private const val CLUSTER_ID_IDENTIFY = 0x0003u
private const val IDENTIFY_COMMAND = 0u
private const val CLUSTER_ID_TEST = 0xFFF1FC05u
private const val TEST_ADD_ARGUMENT_COMMAND = 0X04u
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ import java.util.logging.Level
import java.util.logging.Logger
import kotlinx.coroutines.runBlocking
import matter.controller.MatterController
import matter.controller.ReadData
import matter.controller.ReadRequest
import matter.controller.ReadResponse
import matter.controller.model.AttributePath
import matter.controller.model.EventPath
import matter.devicecontroller.cluster.clusters.BasicInformationCluster

class PairOnNetworkLongImReadCommand(controller: MatterController, credsIssue: CredentialsIssuer?) :
PairingCommand(
Expand All @@ -21,31 +17,6 @@ class PairOnNetworkLongImReadCommand(controller: MatterController, credsIssue: C
DiscoveryFilterType.LONG_DISCRIMINATOR
) {
override fun runCommand() {
val attributePaths =
listOf(
AttributePath(
endpointId = DEFAULT_ENDPOINT,
clusterId = CLUSTER_ID_BASIC,
attributeId = ATTR_ID_LOCAL_CONFIG_DISABLED,
),
AttributePath(
endpointId = DEFAULT_ENDPOINT,
clusterId = CLUSTER_ID_BASIC,
attributeId = GLOBAL_ATTRIBUTE_LIST,
)
)

val eventPaths =
listOf(
EventPath(
endpointId = WILDCARD_ENDPOINT_ID,
clusterId = WILDCARD_CLUSTER_ID,
eventId = WILDCARD_EVENT_ID
)
)

val readRequest: ReadRequest = ReadRequest(eventPaths, attributePaths)

currentCommissioner()
.pairDevice(
getNodeId(),
Expand All @@ -59,9 +30,11 @@ class PairOnNetworkLongImReadCommand(controller: MatterController, credsIssue: C

runBlocking {
try {
val response: ReadResponse = currentCommissioner().read(readRequest)
logger.log(Level.INFO, "Read command succeeded")
validateResponse(response)
val basicInformationCluster =
BasicInformationCluster(controller = currentCommissioner(), endpointId = DEFAULT_ENDPOINT)
val vendorName = basicInformationCluster.readVendorNameAttribute()
val vendorId = basicInformationCluster.readVendorIDAttribute()
logger.log(Level.INFO, "Read command succeeded, Verdor Name:${vendorName} (ID:${vendorId})")
} catch (ex: Exception) {
logger.log(Level.WARNING, "General read failure occurred with error ${ex.message}")
setFailure("read failure")
Expand All @@ -73,37 +46,9 @@ class PairOnNetworkLongImReadCommand(controller: MatterController, credsIssue: C
setSuccess()
}

private fun findAttributeById(successes: List<ReadData>, id: UInt): ReadData.Attribute? {
return successes.filterIsInstance<ReadData.Attribute>().find { it.path.attributeId == id }
}

private fun findEventById(successes: List<ReadData>, id: UInt): ReadData.Event? {
return successes.filterIsInstance<ReadData.Event>().find { it.path.eventId == id }
}

private fun validateResponse(response: ReadResponse) {
require(response.successes.isNotEmpty()) { "Unexpected: response.successes is empty" }
require(response.failures.isEmpty()) { "Unexpected: response.failures is not empty" }

val localConfigDisabledAttribute =
findAttributeById(response.successes, ATTR_ID_LOCAL_CONFIG_DISABLED)
requireNotNull(localConfigDisabledAttribute) { "No local config disabled attribute found." }

// TODO: Add more validation rules as needed
}

companion object {
private val logger = Logger.getLogger(PairOnNetworkLongImReadCommand::class.java.name)

private const val MATTER_PORT = 5540
private const val DEFAULT_ENDPOINT: UShort = 0u
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
private const val CLUSTER_ID_BASIC: UInt = 0x0028u
private const val ATTR_ID_LOCAL_CONFIG_DISABLED: UInt = 16u
private const val EVENT_ID_START_UP: UInt = 0u
private const val GLOBAL_ATTRIBUTE_LIST: UInt = 65531u
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,11 @@
package com.matter.controller.commands.pairing

import com.matter.controller.commands.common.CredentialsIssuer
import java.time.Duration
import java.util.logging.Level
import java.util.logging.Logger
import kotlinx.coroutines.runBlocking
import matter.controller.MatterController
import matter.controller.WriteRequest
import matter.controller.WriteRequests
import matter.controller.WriteResponse
import matter.controller.model.AttributePath
import matter.tlv.AnonymousTag
import matter.tlv.TlvWriter
import matter.devicecontroller.cluster.clusters.BasicInformationCluster

class PairOnNetworkLongImWriteCommand(
controller: MatterController,
Expand All @@ -43,25 +37,6 @@ class PairOnNetworkLongImWriteCommand(
DiscoveryFilterType.LONG_DISCRIMINATOR
) {
override fun runCommand() {
val tlvWriter1 = TlvWriter()
tlvWriter1.put(AnonymousTag, true)
val writeRequests: WriteRequests =
WriteRequests(
requests =
listOf(
WriteRequest(
attributePath =
AttributePath(
endpointId = 0u,
clusterId = CLUSTER_ID_BASIC,
attributeId = ATTR_ID_LOCAL_CONFIG_DISABLED
),
tlvPayload = tlvWriter1.getEncoded()
)
),
timedRequest = Duration.ZERO
)

currentCommissioner()
.pairDevice(
getNodeId(),
Expand All @@ -75,24 +50,13 @@ class PairOnNetworkLongImWriteCommand(

runBlocking {
try {
val response: WriteResponse = currentCommissioner().write(writeRequests)

if (response is WriteResponse.Success) {
logger.log(Level.INFO, "Write command succeeded")
} else if (response is WriteResponse.PartialWriteFailure) {
logger.log(
Level.WARNING,
"Partial write failure occurred with ${response.failures.size} errors"
)
val basicInformationCluster =
BasicInformationCluster(controller = currentCommissioner(), endpointId = DEFAULT_ENDPOINT)
basicInformationCluster.writeNodeLabelAttribute("Test Node Label")
logger.log(Level.INFO, "Write command succeeded")

for ((index, error) in response.failures.withIndex()) {
logger.log(Level.WARNING, "Error ${index + 1}:")
logger.log(Level.WARNING, "Attribute Path: ${error.attributePath}")
logger.log(Level.WARNING, "Exception Message: ${error.ex.message}")
}

setFailure("invoke failure")
}
val nodeLabel = basicInformationCluster.readNodeLabelAttribute()
logger.log(Level.INFO, "Read command succeeded, NodeLabel:${nodeLabel}")
} catch (ex: Exception) {
setFailure("invoke failure: ${ex.message}")
} catch (ex: Exception) {
Expand All @@ -108,9 +72,7 @@ class PairOnNetworkLongImWriteCommand(

companion object {
private val logger = Logger.getLogger(PairOnNetworkLongImWriteCommand::class.java.name)

private const val MATTER_PORT = 5540
private const val CLUSTER_ID_BASIC = 0x0028u
private const val ATTR_ID_LOCAL_CONFIG_DISABLED = 16u
private const val DEFAULT_ENDPOINT: UShort = 0u
}
}
3 changes: 3 additions & 0 deletions kotlin-detect-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ exceptions:
- "**/src/controller/java/generated/java/**/*"

naming:
VariableNaming:
excludes:
- "**/src/controller/java/generated/java/**/*"
FunctionNaming:
excludes:
- "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt"
Expand Down
Loading

0 comments on commit 3f80447

Please sign in to comment.