1. Welcome
Built with the goal of unifying IoT standards, Matter connects smart home devices across various ecosystems like Google Home, Zigbee, Bluetooth Mesh, Z-Wave, and more.
Mobile devices are a central interaction point with smart home devices. If you'd like to build your own Android apps to support Matter devices, we can help you get started fast.
The Google Home Sample App for Matter (GHSA for Matter) showcases the Home Mobile SDK APIs, allowing users to commission and share devices. You can also use the sample app as a learning tool to better understand key Matter concepts, as well as a tool to debug and troubleshoot interactions with Matter devices.
What you'll do
In this Codelab, you'll download the source code for the sample app and learn how to use the Home Mobile SDK to commission and share devices. You'll also learn how to use commissioning and Cluster libraries from the Matter repo (connectedhomeip
).
After you download the sample app, we'll review the source code in Android Studio and implement the following Home Mobile SDK APIs:
You'll also learn more about commissioning concepts, Matter fabrics, and how to control Matter devices.
What you'll need
Before you begin, make sure to complete the following steps:
- Review the Google Home Sample App for Matter Guide.
- Download Android Studio.
- Have an Android O (8.1, API level 27) or newer device available for testing. To make sure that your device has the latest Matter support, review the Verify Matter Modules & Services guide.
- Build a Matter device with On/Off capabilities. This sample app works with a virtual device and an ESP32.
- Build a Matter Virtual Device with the
rootnode_dimmablelight_bCwGYSDpoe
app. When you Create a Matter integration in the Home Developer Console, use0xFFF1
as your Vendor ID and0x8000
as your Product ID. - Build an Espressif Device with the
all-clusters-app
. When you Create a Matter integration in the Home Developer Console, use0xFFF1
as your Vendor ID and0x8001
as your Product ID.
- Build a Matter Virtual Device with the
- Review how to Set up Google Play services.
You don't need a hub, for example a Google Nest Hub (2nd Generation), to commission and control devices with the sample app.
2. Get set up
The Sample app GitHub repository includes third party libraries from the Matter repo (connectedhomeip
). These native libraries are over 50MB, and require the use of Git Large File Storage (LFS).
The codelab starter app is located in the codelab
branch. To start working with the codelab source code, you can download the ZIP file. This ZIP includes the Matter SDK native libraries without the need for Git LFS:
You'll use this codelab
ZIP file to build a working sample.
Codelab versions
The codelab
branch is tagged with the 1.2.2 release of the sample app. To compare your updates as you work through each step, you can download the completed source code for this release.
If you'd like to clone the GitHub repository, follow the instructions on the Sample app README.
Dependencies
We'll guide you through the source code required to share and commission devices, but it might help to be aware of the following dependencies before you get started:
- Home Mobile SDK.
implementation 'com.google.android.gms:play-services-home:16.0.0'
- Matter SDK libraries.
// Native libs implementation fileTree(dir: "third_party/connectedhomeip/libs", include: ["*.jar", "*.so"])
- Material Design. To learn more, refer to MDC-103 Android: Material Theming with Color, Elevation and Type (Kotlin) and Material Theme Builder.
implementation 'com.google.android.material:material:1.5.0'
- Proto DataStore, used to persist app data. Datastore Repositories and Serializers are stored in
java/data
, including schemas for devices and user preferences. To learn more about DataStore, refer to Working with Proto DataStore.implementation "androidx.datastore:datastore:$dataStoreVersion" implementation 'androidx.datastore:datastore-core:1.0.0' implementation 'com.google.protobuf:protobuf-javalite:3.18.0'
- Hilt to persist data and support dependency injection.
kapt 'com.google.dagger:hilt-compiler:2.41' implementation 'com.google.dagger:hilt-android:2.41'
Source code
The user interface and most of the functionality has already been created for you.
For this codelab, we'll be adding Matter functionality to the following files:
java/commissioning/AppCommissioningService
: allows you to commission devices to the development fabricjava/screens/HomeFragment
andjava/screens/HomeViewModel.kt
: includes the Home Mobile SDK commissioning functionalityjava/screens/DeviceViewModel
: includes the Share Device API calls
Each file is commented with the code-block that you'll be modifying, for example:
// CODELAB: add commissioningFunction()
This allows you to quickly locate the corresponding section in the codelab.
3. Commission to Google
Before you can control devices and allow them to communicate with each other within the same fabric, they need to be commissioned by a Commissioner, which in this case is this sample application, the Google Home Sample App for Matter.
It's important to understand the following concepts about Matter commissioning:
- Fabrics allow devices to communicate with each other.
- Fabrics maintain a shared set of unique credentials.
- Ecosystems are responsible for issuing trusted root certificates, assigning fabric IDs, and assigning unique node IDs. An ecosystem is the back-end service of a commissioner, for example the Home Graph for the Google Home ecosystem.
- Devices can be commissioned to more than one fabric (multi-admin feature).
To commission a device, you'll need to use the CommissioningClient API. A call to .commissionDevice()
returns an IntentSender, which launches the proper activity in Google Play Services:
interface CommissioningClient { Task<IntentSender> commissionDevice(CommissioningRequest request); }
In the next sections, we'll go over the minimal code required to commission devices to the Google fabric.
Step 1: Activity Launcher
To handle the IntentSender
from the CommissioningClient
, you can use an ActivityResultLauncher:
private lateinit var commissioningLauncher: ActivityResultLauncher<IntentSenderRequest>
commissioningLauncher = registerForActivityResult( StartIntentSenderForResult() ) { result: ActivityResult -> if (result.resultCode == RESULT_OK) { Timber.d(TAG, "Commissioning succeeded.") } else { Timber.d(TAG, "Commissioning failed. " + result.resultCode) } }
Step 2: Commissioning function
Here's a basic example that uses the CommissioningClient API to commission a device to the Google fabric.
- The commissioning process starts with the
commissionDevice()
function. First, aCommissioningRequest
is defined. With this default configuration, devices are commissioned only to the Local Android fabric. Matter
is the entry point for the Home Mobile SDK. In the next call,.getCommissioningClient
gets a CommissioningClient bythis
(Activity)..commissionDevice()
accepts theCommissioningRequest
.- And finally,
.addOnSuccessListener
is called to process theCommissioningResult
and launch the Google Play Services (GPS) Commission Device Activity.
private fun commissionDevice() { val request: CommissioningRequest = CommissioningRequest.builder().build() Matter.getCommissioningClient(this) .commissionDevice(request) .addOnSuccessListener { result -> commissioningLauncher.launch(IntentSenderRequest.Builder(result).build()) } }
The Local Android Fabric can be leveraged via Android settings to simplify the process of commissioning its devices to other fabrics.
Next, you'll learn how to commission a device to a development fabric.
For an overview of the user interface during the commissioning process, refer to the Google Home Sample App for Matter Guide.
4. Commission to a development fabric
Devices can be commissioned to more than one fabric. To manage trusted pairings, devices store a FabricTable
containing various FabricInfo
members, for example:
- Fabric identification
- Node Id assigned by the fabric to the device
- Vendor Id
- Fabric Id
- Device operational credentials
The administrative domain manager (ADM) defines fabric credentials. In the previous scenario, Google Play Services is the ecosystem that acts as a trusted root certificate authority (CA). When you commission devices to the Local Android fabric, every device includes the same set of fabric credentials, and the same set of CAs.
Custom Commissioning Services
To commission to the Local Android fabric, we used the default parameters to build the CommissioningRequest
in the CommissioningClient API:
val request: CommissioningRequest = CommissioningRequest.builder().build()
If you'd like to control and manage new devices from your app, you need to create a local development fabric and obtain the operational credentials to commission devices. In this scenario, your app becomes a unique, independent ecosystem that assigns devices the appropriate node credentials.
You can inform Home Mobile SDK that you'd like to commission devices to your own fabric by passing a custom service to the CommissioningRequest:
class CommissioningRequest { static CommissioningRequest.Builder builder(); class Builder { Builder setCommissioningService(@Nullable ComponentName commissioningService); CommissioningRequest build(); } }
In the next steps, we'll modify the commissionDevice()
function to use a custom service. We'll also add an Activity Launcher to the Home fragment and use LiveData objects to manage the API flow.
Step 1: Create a GPS Activity Launcher
First, let's create an Activity Launcher to handle the IntentSender
from the CommissioningClient API.
- Open
HomeFragment
in thejava/screens/home/
folder. - Replace the
// CODELAB: commissionDeviceLauncher declaration
comment with the following declaration:// The ActivityResult launcher that launches the "commissionDevice" activity in Google Play // Services. private lateinit var commissionDeviceLauncher: ActivityResultLauncher<IntentSenderRequest>
- Replace the
// CODELAB: commissionDeviceLauncher definition
comment with the following code to register and handle the commissioning Activity result:commissionDeviceLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> // Commission Device Step 5. // The Commission Device activity in GPS has completed. val resultCode = result.resultCode if (resultCode == Activity.RESULT_OK) { Timber.d("CommissionDevice: Success") // We now need to capture the device information for the app's fabric. // Once this completes, a call is made to the viewModel to persist the information // about that device in the app. showNewDeviceAlertDialog(result) } else { viewModel.commissionDeviceFailed(resultCode) } } ```
Step 2: Create LiveData objects
The success callback of the .commissionDevice()
API provides the IntentSender
to be used to launch the Commission Device Activity in Google Play Services. In the HomeViewModel
, we'll create two LiveData objects to report on the result of this API call:
commissionDeviceStatus
to track theTaskStatus
.commissionDeviceIntentSender
to handle the result of the.commissionDevice()
call. This LiveData Object will launch theActivityLauncher
that we just created and display the GPS Commission Device Activity to the user.
- In
private fun setupObservers()
, replace the// CODELAB: commissionDeviceStatus
comment with the following observer:// The current status of the share device action. viewModel.commissionDeviceStatus.observe(viewLifecycleOwner) { status -> Timber.d("commissionDeviceStatus.observe: status [${status}]") }
- Next, replace the
// CODELAB: commissionDeviceIntentSender
comment with the following observer:viewModel.commissionDeviceIntentSender.observe(viewLifecycleOwner) { sender -> Timber.d( "commissionDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]") if (sender != null) { // Commission Device Step 4: Launch the activity described in the IntentSender that // was returned in Step 3 (where the viewModel calls the GPS API to commission // the device). Timber.d("CommissionDevice: Launch GPS activity to commission device") commissionDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build()) viewModel.consumeCommissionDeviceIntentSender() } }
Step 3: Call the API
Now that we've written the code to handle the API flow, it's time to call the API, pass in a custom service (that we'll define in the next step), and post to our LiveData objects.
- Open
HomeViewModel.kt
in thejava/screens/home/
folder. - Replace the
// CODELAB: commissionDevice
comment with the followingcommissionDeviceRequest
.setCommissioningService
bindsAppCommissioningService
to aCommissioningService
instance, returned in a callback function. When you pass a custom service, Home Mobile SDK will first commission devices to the Google fabric, then send the onboarding payload back to theAppCommissioningService
.fun commissionDevice(context: Context) { _commissionDeviceStatus.postValue(TaskStatus.InProgress) val commissionDeviceRequest = CommissioningRequest.builder() .setCommissioningService(ComponentName(context, AppCommissioningService::class.java)) .build()
- Call
.getCommissioningClient()
, then call.commissionDevice()
.Matter.getCommissioningClient(context) .commissionDevice(commissionDeviceRequest)
To complete our commissionDevice
function, add an addOnSuccessListener
and addOnFailureListener
and post to the LiveData objects:
.addOnSuccessListener { result -> // Communication with fragment is via livedata _commissionDeviceIntentSender.postValue(result) } .addOnFailureListener { error -> Timber.e(error) _commissionDeviceStatus.postValue( TaskStatus.Failed("Failed to to get the IntentSender.", error) } }
After using the sender, consumeCommissionDeviceIntentSender()
should be called to avoid receiving the sender again after a configuration change.
/** * Consumes the value in [_commissionDeviceIntentSender] and sets it back to null. Needs to be * called to avoid re-processing the IntentSender after a configuration change (where the LiveData * is re-posted). */ fun consumeCommissionDeviceIntentSender() { _commissionDeviceIntentSender.postValue(null) }
5. Create a CommissioningService
In the commissionDevice()
function, we requested to get a CommissioningService from the CommissioningClient API. In this flow, the CommissioningClient API commissions devices to the Local Android fabric first, then returns a callback that includes the CommissioningRequestMetadata object:
public interface CommissioningService { interface Callback { void onCommissioningRequested(CommissioningRequestMetadata metadata); } }
Now, we have to inherit the CommissioningService.Callback and provide the functionality required to commission devices to our sample app. Here's an example of a basic CommissioningService implementation:
class MatterCommissioningService : Service(), CommissioningService.Callback { private val commissioningServiceDelegate = CommissioningService.Builder(this) .setCallback(this) .build() override fun onBind(intent: Intent) = commissioningServiceDelegate.asBinder() override fun onCommissioningRequested(metadata: CommissioningRequestMetadata) { // perform commissioning commissioningServiceDelegate .sendCommissioningComplete(CommissioningCompleteMetadata.builder().build()) } }
Step 1: Explore the custom AppCommissioningService
To help you get started, we've already defined the basic class structure for our custom CommissioningService. Here's a quick overview of the service functionality. To follow along, open AppCommissioningService
in java/commissioning
.
We've added the following imports for the Home Mobile SDK APIs:
import com.google.android.gms.home.matter.commissioning.CommissioningCompleteMetadata import com.google.android.gms.home.matter.commissioning.CommissioningRequestMetadata import com.google.android.gms.home.matter.commissioning.CommissioningService
AppCommissioningService
also includes libraries from the Matter repo (connectedhomeip
):
import com.google.home_sample_app_for_matter.chip.ChipClient
Finally, the service includes imports to support Hilt and Kotlin coroutines.
Next, we create the constructor and set a few things up, including the commissioningServiceDelegate
, which we'll use to let Google Play Services know when commissioning is complete.
private lateinit var commissioningServiceDelegate: CommissioningService ... commissioningServiceDelegate = CommissioningService.Builder(this).setCallback(this).build()
Now it's time to add the commissioning functions.
Step 2: Override onCommissioningRequested
To commission devices to the app's development fabric, complete the following steps:
- Open
AppCommissioningService
injava/commissioning
. - Locate the
onCommissioningRequested()
function. We've provided a log message that prints out theCommissioningRequestMetadata
. Replace the// CODELAB: onCommissioningRequested()
comment to start theserviceScope
coroutine and get thedeviceId
.// Perform commissioning on custom fabric for the sample app. serviceScope.launch { val deviceId = devicesRepository.incrementAndReturnLastDeviceId()
- Perform commissioning. For this step, we can pass the device information returned in the CommissioningRequestMetadata object. The
ChipClient
uses this metadata information to create a secure channel between the GHSA for Matter app and your device.Timber.d("Commissioning: App fabric -> ChipClient.establishPaseConnection(): deviceId [${deviceId}]") chipClient.awaitEstablishPaseConnection( deviceId, metadata.networkLocation.ipAddress.hostAddress!!, metadata.networkLocation.port, metadata.passcode) Timber.d("Commissioning: App fabric -> ChipClient.commissionDevice(): deviceId [${deviceId}]") chipClient.awaitCommissionDevice(deviceId, null)
- Use the
commissioningServiceDelegate
to let Google Play Services know that commissioning is complete. In.sendCommissioningComplete()
, pass the CommissioningCompleteMetadata.Timber.d("Commissioning: Calling commissioningServiceDelegate.sendCommissioningComplete()") commissioningServiceDelegate .sendCommissioningComplete( CommissioningCompleteMetadata.builder().setToken(deviceId.toString()).build()) .addOnSuccessListener { Timber.d("Commissioning: OnSuccess for commissioningServiceDelegate.sendCommissioningComplete()") } .addOnFailureListener { ex -> Timber.e(ex, "Commissioning: Failed to send commissioning complete.", ex) } }
Run the app
Now that all of the required code is in place to commission to our local fabric, it's time to test it. Choose your Android device, and run the app. From the Home screen, tap Add Device and complete the steps to commission your device.
When commissioning completes, your device now participates in two fabrics: the Local Android fabric, and your local development fabric. Each fabric has its own set of credentials and a unique, 64-bit fabric ID.
6. Control devices
Commissioning to a development fabric allows you to use the libraries from the Matter repo (connectedhomeip
) to control devices from the sample app.
We've created some helper classes to make it easier to access device Clusters and send commands. To learn more, open ClustersHelper
in java/clusters
. This Singleton helper imports the following libraries to access device information:
import chip.devicecontroller.ChipClusters import chip.devicecontroller.ChipStructs
We can use this class to get the On/Off Cluster for a device, then call .toggle
:
suspend fun toggleDeviceStateOnOffCluster(deviceId: Long, endpoint: Int) { Timber.d("toggleDeviceStateOnOffCluster())") val connectedDevicePtr = try { chipClient.getConnectedDevicePointer(deviceId) } catch (e: IllegalStateException) { Timber.e("Can't get connectedDevicePointer.") return } return suspendCoroutine { continuation -> getOnOffClusterForDevice(connectedDevicePtr, endpoint) .toggle( object : ChipClusters.DefaultClusterCallback { override fun onSuccess() { continuation.resume(Unit) } override fun onError(ex: Exception) { Timber.e("readOnOffAttribute command failure: $ex") continuation.resumeWithException(ex) } }) } }
Toggle a device
After you commission a device, the payload returned in the CommissioningResult gets added to the DataStore. This gives our app access to device information that we can use to send commands.
Matter apps are event driven. When the Matter stack is initialized, Cluster services listen for incoming messages. Once a device is commissioned, Matter clients send commands over the secure operational channel that was established during device commissioning.
On the device, packets are validated, decrypted, then dispatched with a callback. Callback functions include the EndpointId, ClusterId, and AttributeId, accessible from the attributePath
. For example, this code can be implemented on a Matter device:
void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, uint16_t size, uint8_t * value) { // handle callback ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; }
In the next steps, you'll use the Matter SDK and ClustersHelper
to toggle a device.
- Go to
DeviceViewModel
injava/screens/device
. - Locate the
updateDeviceStateOn
function. - Replace the
// CODELAB: toggle
comment with the code to callclustersHelper
, then update the device repository:Timber.d("Handling real device") try { clustersHelper.setOnOffDeviceStateOnOffCluster(deviceUiModel.device.deviceId, isOn, 1) devicesStateRepository.updateDeviceState(deviceUiModel.device.deviceId, true, isOn) } catch (e: Throwable) { Timber.e("Failed setting on/off state") }
This function is called from DeviceFragment
:
// Change the on/off state of the device binding.onoffSwitch.setOnClickListener { val isOn = binding.onoffSwitch.isChecked viewModel.updateDeviceStateOn(selectedDeviceViewModel.selectedDeviceLiveData.value!!, isOn) }
Run the app
Run the app to reload your updates. From the Home screen, toggle your device on and off.
7. Share devices with other ecosystems
Sharing a device is referred to as multi-admin flow in the Matter specification.
In the previous steps, we learned that the Home Mobile SDK makes it possible to commission devices to the Local Android fabric and also to a development fabric for the sample app. This is an example of multi-admin flow, where devices can be commissioned to more than one fabric.
Now, you may want to share devices with even more fabrics, especially if this is a household where people have their own preferences when it comes to applications and platforms.
The Home Mobile SDK provides this functionality in the ShareDeviceRequest API, allowing you to:
- Open a temporary commissioning window for devices.
- Change the state of your devices, enabling them to be commissioned to another fabric.
- Control your devices from other apps and ecosystems.
In the next steps, you'll use the Home Mobile SDK to share devices.
Step 1: Create a GPS Activity Launcher
Similar to the Commissioning Activity Launcher that we created when we commissioned to a development fabric, we've created a Share Device Activity Launcher to handle the IntentSender
from the CommissioningClient API.
- Open
DeviceFragment
in thejava/screens/device/
folder. - Replace the
// CODELAB: shareDeviceLauncher definition
comment with the following code to register and handle the.shareDevice()
Activity result:shareDeviceLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> // Share Device Step 5. // The Share Device activity in GPS (step 4) has completed. val resultCode = result.resultCode if (resultCode == RESULT_OK) { Timber.d("ShareDevice: Success") viewModel.shareDeviceSucceeded(selectedDeviceViewModel.selectedDeviceLiveData.value!!) } else { viewModel.shareDeviceFailed( selectedDeviceViewModel.selectedDeviceLiveData.value!!, resultCode) } }
Step 2: Review LiveData objects
The success callback of the .shareDevice()
API provides the IntentSender
to be used to launch the Share Device Activity in Google Play Services. In the DeviceViewModel
, we've created two LiveData objects to report on the result of this API call:
_shareDeviceStatus
to track theTaskStatus
.// The current status of the share device action. viewModel.shareDeviceStatus.observe(viewLifecycleOwner) { status -> val isButtonEnabled = status !is InProgress updateShareDeviceButton(isButtonEnabled) if (status is TaskStatus.Failed) { showAlertDialog(errorAlertDialog, status.message, status.cause!!.toString()) } }
_shareDeviceIntentSender
to handle the result of the.sharedevice()
call.viewModel.shareDeviceIntentSender.observe(viewLifecycleOwner) { sender -> Timber.d("shareDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]") if (sender != null) { // Share Device Step 4: Launch the activity described in the IntentSender that // was returned in Step 3 (where the viewModel calls the GPS API to commission // the device). Timber.d("ShareDevice: Launch GPS activity to share device") shareDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build()) viewModel.consumeShareDeviceIntentSender() } }
In the next steps, we'll use these LiveData objects in our .shareDevice()
API call.
Step 3: Call the API
Now it's time to initiate a share device task.
- Open
DeviceViewModel.kt
in thejava/screens/device/
folder. - Locate the
shareDevice()
function. Replace the// CODELAB: shareDevice
comment with the ShareDeviceRequest. TheDeviceDescriptor
provides specific information about the device such as its Vendor Id, Product Id, and deviceType. In this example, we hard-code the values.Timber.d("ShareDevice: Setting up the IntentSender") val shareDeviceRequest = ShareDeviceRequest.builder() .setDeviceDescriptor(DeviceDescriptor.builder().build()) .setDeviceName("temp device name")
- Set the CommissioningWindow and parameters. At this point, the temporary commissioning window is open on the device.
.setCommissioningWindow( CommissioningWindow.builder() .setDiscriminator(Discriminator.forLongValue(DISCRIMINATOR)) .setPasscode(SETUP_PIN_CODE) .setWindowOpenMillis(SystemClock.elapsedRealtime()) .setDurationSeconds(OPEN_COMMISSIONING_WINDOW_DURATION_SECONDS.toLong()) .build()) .build()
- Call
.getCommissioningClient()
, only this time, use the.shareDevice()
API. The success callback of thecommissioningClient.shareDevice()
API provides the IntentSender to be used to launch the Share Device Activity in Google Play Services.Matter.getCommissioningClient(activity) .shareDevice(shareDeviceRequest)
- To complete our
shareDevice
function, add anaddOnSuccessListener
andaddOnFailureListener
and post to the LiveData objects:.addOnSuccessListener { result -> Timber.d("ShareDevice: Success getting the IntentSender: result [${result}]") // Communication with fragment is via livedata _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide) _shareDeviceIntentSender.postValue(result) } .addOnFailureListener { error -> Timber.e(error) _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide) _shareDeviceStatus.postValue( TaskStatus.Failed("Setting up the IntentSender failed", error)) }
After using the sender, consumeShareDeviceIntentSender
should be called to avoid receiving the sender again after a configuration change.
/** * Consumes the value in [_shareDeviceIntentSender] and sets it back to null. Needs to be called * to avoid re-processing an IntentSender after a configuration change where the LiveData is * re-posted. */ fun consumeShareDeviceIntentSender() { _shareDeviceIntentSender.postValue(null) }
Run the app
To share your Matter device with other ecosystems, you'll need to have another platform installed on your Android device. We've created another instance of the sample app that you can use as the target commissioner.
Once you have the target commissioner installed on your Android device, verify that you can share your Matter device. The target commissioner app is labeled GHSAFM-TC.
Your devices can now participate in three fabrics:
- The Local Android fabric.
- Your development fabric (this app).
- This third fabric that you've just shared the device with.
8. Next Steps
Congratulations
Congratulations, you've successfully completed this Codelab and learned how to commission and share devices using the Home Mobile SDK.
If you're having issues with the sample app, try completing the steps to verify your environment:
If you have questions about using the sample app or discover a code bug, you can submit issues to the Issue Tracker in the GitHub repository:
To get official guidance from Google on technical questions, use the Smart Home Developer Forum:
To get technical support from the community, use the google-smart-home
tag on Stack Overflow: