Creating a Matter Virtual Device

HyoJung Lee

Matter is an open-source connectivity standard for smart home and Internet of Things (IoT) devices. It is a secure, reliable, and seamless cross-platform protocol for connecting compatible devices and systems with one another.

SmartThings provides the Matter virtual device application and the SmartThings Home APIs to help you quickly develop Matter devices and use the SmartThings ecosystem without needing to build your own IoT ecosystem.

When Matter was first introduced, because few devices supported it, platform companies struggled to test and optimize Matter support on their own devices. To alleviate this issue, Samsung SmartThings developed the Matter virtual device application, which can be used to test and optimize various device types, including those that have not yet been released. The Matter virtual device is part of the Matter open source project you can create and test Matter devices virtually too.

In this tutorial, you will learn how to create an occupancy sensor as a Matter virtual device that you can control using the SmartThings application. You will also gain an understanding of the concept of clusters on Matter devices.

For more information about SmartThings Matter, see Matter in SmartThings.


Prerequisites

To follow along with this tutorial, you need the following hardware and software:

  • Host PC running Windows 10 or higher or Ubuntu 20.04 (x64)
  • Android Studio (latest version recommended)
  • Java SE Development Kit (JDK) 11 or higher
  • Devices connected to the same network:
    • Mobile device running Android 8.0 Oreo or higher
    • Mobile device with the SmartThings application installed
    • Matter-enabled SmartThings Station onboarded with the same Samsung account as the SmartThings application

※ For Ubuntu, to set up the development environment:

Step 1. Turn on Developer Mode and enable USB debugging on your mobile device.

Step 2. Install the required OS-specific dependencies from your terminal:

$ sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \
libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev \
python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev

Step 3. From the SDK Manager in Android Studio, install SDK Platform 26 and NDK version 22.1.7171670.

Step 4. Register the NDK path to the PATH environment variable:

export ANDROID_NDK_HOME=[NDK PATH]
export PATH=$PATH:${ANDROID_NDK_HOME}

Step 5. Install Kotlin compiler (kotlinc) version 1.5.10.

Step 6. Register the kotlinc path to the PATH environment variable.

export KOTLINC_HOME=[KOTLINC PATH]/bin
export PATH=$PATH:${KOTLINC_HOME}

Implement the occupancy sensor device type

To implement the occupancy sensor device type in the Matter virtual device application:

Step 1. Download the sample application project and open it in Android Studio.

Sample code - Virtual Device App
(11.11MB) Nov 21, 2023

Step 2. Build and run the sample application. The application implements an on/off switch device type as an example.

Step 3. Go to the file path feature > main > java > com.matter.virtual.device.app.feature.main.

Step 4. To add the occupancy sensor device type to the application home screen, in the MainFragment.kt file, select the device type:

// Todo 1
MainUiState.Start -> {
  val itemList =
    listOf(
      Device.OnOffSwitch,        // Sample device type
      // Todo 1
      Device.OccupancySensor,    // Add the occupancy sensor
  ) 

Retrieve cluster values

Clusters are the functional building block elements of the data model. A cluster can be an interface, a service, or an object class, and it is the lowest independent functional element in the data model.

Each Matter device supports a defined set of relevant clusters that can interact with your preferred controller (such as SmartThings). This allows for easy information retrieval, behavior setting, event notifications, and more.

The following steps are implemented in the file OccupancySensorViewModel.kt at the path feature > sensor > java > com.matter.virtual.device.app.feature.sensor.

To retrieve the relevant cluster values from the device through the ViewModel:

Step 1. Retrieve the current occupancy status. The Boolean value is used by OccupancyFragment to update the UI.

// Todo 2
private val _occupancy: StateFlow<Boolean> = getOccupancyFlowUseCase()
val occupancy: LiveData<Boolean>
  get() = _occupancy.asLiveData()

Step 2. Retrieve the current battery status. The integer value is used by OccupancyFragment to update the UI.

//Todo 3
private val _batteryStatus: MutableStateFlow<Int> =
  getBatPercentRemainingUseCase() as MutableStateFlow<Int>
val batteryStatus: LiveData<Int>
  get() = _batteryStatus.asLiveData()

Step 3. When the "Occupancy" button in OccupancyFragment is pressed, use the SetOccupancyUseCase() function to update the occupancy status Boolean value.

// Todo 4
viewModelScope.launch {
  Timber.d("current value = ${_occupancy.value}")
  if (_occupancy.value) {
    Timber.d("set value = false")
    setOccupancyUseCase(false)
  } else {
    Timber.d("set value = true")
    setOccupancyUseCase(true)
  }
}

Step 4. When the "Battery" slider in OccupancyFragment is moved, store the slider progress as the battery status.

// Todo 5
batteryStatus.value = progress

Step 5. When the "Battery" slider in OccupancyFragment is moved, use the updateBatterySeekbarProgress() function to update the battery status value on the slider. Use SetBatPercentRemainingUseCase() to update the battery status integer value.

// Todo 6
viewModelScope.launch {
  updateBatterySeekbarProgress(progress)
  setBatPercentRemainingUseCase(progress)
}

Monitor cluster values

The observe() function monitors for and reacts to changes in a cluster value.

The following steps are implemented in the file OccupancySensorFragment.kt at the path feature > sensor > java > com.matter.virtual.device.app.feature.sensor.

To monitor changes in the virtual occupancy sensor’s cluster values:

Step 1. Trigger updating the occupancy status of the virtual device when the ”Occupancy” button is pressed.

// Todo 7
binding.occupancyButton.setOnClickListener { viewModel.onClickButton() }

Step 2. Use the onProgressChanged() function to update the fragment UI through live data from the ViewModel. The onStopTrackingTouch() function triggers updating the battery status when touch tracking on the “Battery” slider stops.

// Todo 8
binding.occupancySensorBatteryLayout.titleText.text = getString(R.string.battery)
binding.occupancySensorBatteryLayout.seekbarData =
  SeekbarData(progress = viewModel.batteryStatus)
binding.occupancySensorBatteryLayout.seekbar.setOnSeekBarChangeListener(
  object : SeekBar.OnSeekBarChangeListener {
    override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
      viewModel.updateBatterySeekbarProgress(progress)
    }

    override fun onStartTrackingTouch(seekBar: SeekBar) {}

    override fun onStopTrackingTouch(seekBar: SeekBar) {
      viewModel.updateBatteryStatusToCluster(seekBar.progress)
    }
  }
)

Step 3. Monitor the occupancy status and update the fragment UI when it changes.

// Todo 9
viewModel.occupancy.observe(viewLifecycleOwner) {
  if (it) {
    binding.occupancyValueText.text = getString(R.string.occupancy_state_occupied)
    binding.occupancyButton.setImageResource(R.drawable.ic_occupied)
  } else {
    binding.occupancyValueText.text = getString(R.string.occupancy_state_unoccupied)
    binding.occupancyButton.setImageResource(R.drawable.ic_unoccupied)
  }
}

Step 4. Monitor the battery status and update the fragment UI when it changes.

// Todo 10
viewModel.batteryStatus.observe(viewLifecycleOwner) {
  val text: String = getString(R.string.battery_format, it)
  binding.occupancySensorBatteryLayout.valueText.text =
    Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)
}

Test the virtual device

To test the virtual occupancy sensor device:

Step 1. Build and run the project on your Android device. The application’s home screen shows the sample on/off switch device type and the occupancy sensor device type that you just implemented.

Step 2. To create a virtual occupancy sensor device, select Occupancy sensor and follow the instructions to receive a QR code.
Text

Step 3. Within the SmartThings application on the other mobile device, onboard the occupancy sensor by scanning the QR code.
Text

Step 4. Change the occupancy or battery status of the virtual occupancy sensor in the virtual device application. The values are synchronized to the SmartThings application.
Text


Conclusion

This tutorial demonstrates how you can implement the occupancy sensor device type in the Matter virtual device application and create a virtual occupancy sensor for testing purposes. To learn about implementing other device types, go to Code Lab (Matter: Create a virtual device and make an open source distribution). The Code Lab also describes how to contribute to the Matter open source project.