Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android]Initial implementation of Kotlin Matter Controller #29574

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions kotlin-detect-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ complexity:
- "**/src/controller/java/src/chip/onboardingpayload/OnboardingPayload.kt"
- "**/src/controller/java/src/chip/tlv/TlvReader.kt"
- "**/src/controller/java/src/chip/tlv/TlvWriter.kt"
- "**/src/controller/java/src/matter/controller/MatterControllerImpl.kt"
- "**/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt"
- "**/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt"
- "**/src/controller/java/tests/chip/onboardingpayload/ManualCodeTest.kt"
- "**/src/controller/java/tests/chip/onboardingpayload/QRCodeTest.kt"
Expand Down
33 changes: 33 additions & 0 deletions src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,39 @@ kotlin_library("chipcluster_test") {
kotlinc_flags = [ "-Xlint:deprecation" ]
}

kotlin_library("kotlin_matter_controller") {
output_name = "KotlinMatterController.jar"

deps = [
":java",
"${chip_root}/third_party/java_deps:annotation",
]

sources = [
"src/matter/controller/CompletionListenerAdapter.kt",
"src/matter/controller/ControllerParams.kt",
"src/matter/controller/InteractionClient.kt",
"src/matter/controller/MatterController.kt",
"src/matter/controller/MatterControllerException.kt",
"src/matter/controller/MatterControllerImpl.kt",
"src/matter/controller/Messages.kt",
"src/matter/controller/OperationalKeyConfig.kt",
"src/matter/controller/model/Paths.kt",
"src/matter/controller/model/States.kt",
]

if (matter_enable_java_compilation) {
deps += [
"${chip_root}/third_party/java_deps:json",
"${chip_root}/third_party/java_deps:kotlin-stdlib",
"${chip_root}/third_party/java_deps:kotlinx-coroutines-core-jvm",
"${chip_root}/third_party/java_deps/stub_src",
]
} else {
deps += [ ":android" ]
}
}

group("unit_tests") {
deps = [
":chipcluster_test",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 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.
*
*/
package matter.controller

import chip.devicecontroller.ChipDeviceController
import java.util.logging.Level
import java.util.logging.Logger

class CompletionListenerAdapter(val listener: MatterController.CompletionListener) :
chip.devicecontroller.ChipDeviceController.CompletionListener {

override fun onConnectDeviceComplete() = listener.onConnectDeviceComplete()

override fun onStatusUpdate(status: Int) = listener.onStatusUpdate(status)

override fun onPairingComplete(errorCode: Int) = listener.onPairingComplete(errorCode)

override fun onPairingDeleted(errorCode: Int) = listener.onPairingDeleted(errorCode)

override fun onNotifyChipConnectionClosed() = listener.onNotifyChipConnectionClosed()

override fun onCommissioningComplete(nodeId: Long, errorCode: Int) =
listener.onCommissioningComplete(nodeId, errorCode)

override fun onCommissioningStatusUpdate(nodeId: Long, stage: String?, errorCode: Int) =
listener.onCommissioningStatusUpdate(nodeId, stage, errorCode)

override fun onReadCommissioningInfo(
vendorId: Int,
productId: Int,
wifiEndpointId: Int,
threadEndpointId: Int
) = listener.onReadCommissioningInfo(vendorId, productId, wifiEndpointId, threadEndpointId)

override fun onOpCSRGenerationComplete(csr: ByteArray) = listener.onOpCSRGenerationComplete(csr)

override fun onError(error: Throwable) = listener.onError(error)

override fun onCloseBleComplete() {
logger.log(Level.INFO, "Not implemented, override the abstract function.")
}

companion object {
private val logger = Logger.getLogger(MatterController::class.java.simpleName)

fun from(
listener: MatterController.CompletionListener?
): chip.devicecontroller.ChipDeviceController.CompletionListener? {
if (listener == null) {
return null
}
return CompletionListenerAdapter(listener)
}
}
}
42 changes: 42 additions & 0 deletions src/controller/java/src/matter/controller/ControllerParams.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2023 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.
*
*/
package matter.controller

/**
* Parameters representing initialization arguments for [MatterController].
*
* @param operationalKeyConfig An optional signing configuration for operational control of devices.
* @param udpListenPort A port for UDP communications, or [UDP_PORT_AUTO] to select automatically.
* @param vendorId The identifier for the vendor using this controller.
* @param countryCode The Regulatory Location country code.
*/
class ControllerParams
@JvmOverloads
constructor(
val operationalKeyConfig: OperationalKeyConfig? = null,
val udpListenPort: Int = UDP_PORT_AUTO,
val vendorId: Int = VENDOR_ID_TEST,
val countryCode: String? = null,
) {
companion object {
/** Matter assigned vendor ID for Google. */
const val VENDOR_ID_TEST = 0xFFF1
/** Indicates that the UDP listen port should be chosen automatically. */
const val UDP_PORT_AUTO = 0
}
}
59 changes: 59 additions & 0 deletions src/controller/java/src/matter/controller/InteractionClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2023 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.
*
*/
package matter.controller

import kotlinx.coroutines.flow.Flow

interface InteractionClient {
/**
* Subscribes to periodic updates of all attributes and events from a device.
*
* @param request The Subscribe command's path and arguments.
* @return A Flow of SubscriptionState representing the subscription's state updates.
*/
fun subscribe(request: SubscribeRequest): Flow<SubscriptionState>

/**
* Issues a read request to a target device for specified attributes and events.
*
* @param request Read command's path and arguments.
* @return A response to the read request.
* @throws Generic Exception if an error occurs during the read operation.
*/
suspend fun read(request: ReadRequest): ReadResponse

/**
* Issues attribute write requests to a target device.
*
* @param writeRequests A list of attribute WriteRequest.
* @return A response to the write request.
* @throws Generic Exception or MatterControllerException if an error occurs during the write
* operation.
*/
suspend fun write(writeRequests: WriteRequests): WriteResponse

/**
* Invokes a command on a target device.
*
* @param request Invoke command's path and arguments.
* @return A response to the invoke request.
* @throws Generic Exception or MatterControllerException if an error occurs during the invoke
* operation.
*/
suspend fun invoke(request: InvokeRequest): InvokeResponse
}
107 changes: 107 additions & 0 deletions src/controller/java/src/matter/controller/MatterController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2023 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.
*
*/
package matter.controller

import java.io.Closeable

/** Controller interface for interacting with a CHIP device. */
interface MatterController : Closeable, InteractionClient {
/** Interface for listening to callbacks from the MatterController. */
interface CompletionListener {
/** Notifies the completion of the "ConnectDevice" command. */
fun onConnectDeviceComplete()

/** Notifies the pairing status. */
fun onStatusUpdate(status: Int)

/** Notifies the completion of pairing. */
fun onPairingComplete(errorCode: Int)

/** Notifies the deletion of a pairing session. */
fun onPairingDeleted(errorCode: Int)

/** Notifies that the CHIP connection has been closed. */
fun onNotifyChipConnectionClosed()

/** Notifies the completion of commissioning. */
fun onCommissioningComplete(nodeId: Long, errorCode: Int)

/** Notifies the completion of reading commissioning information. */
fun onReadCommissioningInfo(
vendorId: Int,
productId: Int,
wifiEndpointId: Int,
threadEndpointId: Int
)

/** Notifies the completion of each stage of commissioning. */
fun onCommissioningStatusUpdate(nodeId: Long, stage: String?, errorCode: Int)

/** Notifies the listener of an error. */
fun onError(error: Throwable)

/** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */
fun onOpCSRGenerationComplete(csr: ByteArray)
}

/**
* Sets a completion listener for receiving controller events.
*
* @param listener The listener to set.
*/
fun setCompletionListener(listener: CompletionListener?)

/**
* Commissions a device into a Matter fabric.
*
* @param nodeId The ID of the node to connect to.
* @param address The IP address at which the node is located.
* @param port The port at which the node is located.
* @param discriminator A 12-bit value used to discern between multiple commissionable Matter
* device advertisements.
* @param pinCode The pincode for this node.
*/
fun pairDevice(
nodeId: Long,
address: String,
port: Int,
discriminator: Int,
pinCode: Long,
)

/**
* Removes pairing for a paired device. If the device is currently being paired, it will stop the
* pairing process.
*
* @param nodeId The remote device ID.
*/
fun unpairDevice(nodeId: Long)

/**
* Establishes a secure PASE connection to the given device via IP address.
*
* @param nodeId The ID of the node to connect to.
* @param address The IP address at which the node is located.
* @param port The port at which the node is located.
* @param setupPincode The pincode for this node.
*/
fun establishPaseConnection(nodeId: Long, address: String, port: Int, setupPincode: Long)

/** Closes any active connections through this device controller. */
override fun close()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 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.
*
*/
package matter.controller

class MatterControllerException(errorCode: Long, message: String? = null) :
RuntimeException(message ?: "Error Code $errorCode") {

val errorCode: Long = errorCode
}
Loading