Home API Usage
Below you can find examples of using the Home API.
Commissioner APIs
Commission a Device
Begin by creating a CommissioningClient
instance:
val commissioningClient = Matter.getCommissioningClient()
Request to start commission of your device:
fun startCommissionDevice(context: Context) {
viewModelScope.launch {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.commissionDevice(context)
}
}
Get a result of commissioning:
fun commissionDeviceSuccess(activityResult: ActivityResult) {
val result = CommissioningResult.fromIntentSenderResult(activityResult)
Timber.d("deviceId:${result.deviceId}, deviceName:${result.deviceName}")
}
Full code:
@HiltViewModel
class MainViewModel : ViewModel() {
private val _intentSender = MutableLiveData<IntentSender?>()
val intentSender: LiveData<IntentSender?> get() = _intentSender
fun startCommissionDevice(context: Context) {
viewModelScope.launch {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.commissionDevice(context)
_intentSender.value = intentSender
}
}
fun commissionDeviceSuccess(activityResult: ActivityResult) {
val result = CommissioningResult.fromIntentSenderResult(activityResult)
viewModelScope.launch {
dataStoreRepository.addDevice(Device(result.deviceId, result.deviceName))
}
}
fun clearIntentSender() {
_intentSender.postValue(null)
}
}
Sharing a Device
Begin by creating a CommissioningClient
instance:
val commissioningClient = Matter.getCommissioningClient()
Request to start sharing of your device:
fun shareDevice(context: Context, deviceId: String) {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.shareDevice(context, CommissioningClient.ShareDeviceRequest(deviceId))
}
Get a result of sharing your device:
You will receive the device delete event through onDeviceDeleted
from IHomeServiceListener
.
Full code:
@AndroidEntryPoint
class LightFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val layoutShareDeviceBinding = setupShareDeviceLayout()
layoutShareDeviceBinding.shareButton.setOnClickListener {
viewModel.shareDevice(requireContext())
}
}
}
@HiltViewModel
class LightViewModel : ViewModel() {
private val _intentSender = MutableLiveData<IntentSender?>()
val intentSender: LiveData<IntentSender?> get() = _intentSender
fun shareDevice(context: Context) {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.shareDevice(
context,
CommissioningClient.ShareDeviceRequest(deviceId)
)
_intentSender.value = intentSender
}
fun clearIntentSenderForShareDevice() {
_intentSender.postValue(null)
}
}
Removing a Device
Begin by creating a CommissioningClient
instance:
val commissioningClient = Matter.getCommissioningClient()
Request to start removal of your device:
fun shareDevice(context: Context, deviceId: String) {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.removeDevice(context, CommissioningClient.RemoveDeviceRequest(deviceId))
}
Get a result of your device removal:
info
There is no result for deviceDevice
.
Full code:
@AndroidEntryPoint
class LightFragment : Fragment() {
protected abstract fun setupAppbar(): LayoutAppbarBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupAppbar().toolbarMore.setOnClickListener {
showMoreMenuPopup(it)
}
}
private fun showMoreMenuPopup(anchor: View) {
val items = listOf(
MoreMenuItem(
MoreMenuItem.Type.REMOVE_DEVICE,
R.drawable.round_delete_outline_24,
R.color.red,
getString(R.string.remove_device)
)
)
ListPopupHelper.getListPopup(
anchor,
requireContext(),
MoreMenuAdapter(requireContext(), items)
) { _, _, position, _ ->
val item = items[position]
when (item.type) {
MoreMenuItem.Type.REMOVE_DEVICE -> {
viewModel.removeDevice(requireContext())
}
}
}.show()
}
}
@HiltViewModel
class LightViewModel : ViewModel() {
private val _intentSender = MutableLiveData<IntentSender?>()
val intentSender: LiveData<IntentSender?> get() = _intentSender
fun removeDevice(context: Context) {
val commissioningClient = Matter.getCommissioningClient()
val intentSender = commissioningClient.removeDevice(
context,
CommissioningClient.RemoveDeviceRequest(deviceId)
)
_intentSender.value = intentSender
}
fun clearIntentSenderForRemoveDevice() {
_intentSender.postValue(null)
}
}
Controller APIs
Control a Device
Begin by creating a MatterClient
instance:
val matterClient = Matter.getClient(context)
Get a device by device ID:
val device = matterClient.getDevice(deviceId)
Get a Capability of the device:
/* Switch Device */
val switchCapability = device.readCapability(Switch)
/* Light Device */
val lightCapability = device.readCapability(ColorControl)
Control the device using the APIs supported by the Capability:
/* Switch Device */
switchCapability.on()
switchCapability.off()
/* Light Device */
lightCapability.setColor(hue = 24.5, saturation = 78.6)
Get attributes of the device:
/*
* Switch Device
* Get the current state of switch
*/
private val _onOff = MutableLiveData(false)
val onOff: LiveData<Boolean> get() = _onOff
device.readCapability(Switch)?.onOff?.collect { onOff ->
_onOff.value = onOff
}
Full code:
@AndroidEntryPoint
class LightFragment : Fragment() {
override val viewModel by viewModels<LightViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupObservers()
}
fun setupObservers() {
viewModel.onOff.observe(viewLifecycleOwner) {
if (it) {
binding.power.value.text = getString(R.string.on)
binding.power.actionButton.setImageResource(R.drawable.ic_power_on)
} else {
binding.power.value.text = getString(R.string.off)
binding.power.actionButton.setImageResource(R.drawable.ic_power_off)
}
}
}
@HiltViewModel
class LightViewModel @Inject constructor(
homeRepository: HomeRepository,
savedStateHandle: SavedStateHandle
) : ViewModel() {
protected lateinit var device: Device
private val _onOff = MutableLiveData(false)
val onOff: LiveData<Boolean> get() = _onOff
init {
viewModelScope.launch {
device = homeRepository.getHomeClient().getDevice(it.deviceId) as Device
device.readCapability(Switch)?.onOff?.collect { onOff ->
_onOff.value = onOff
}
}
}
fun switchOnOff(context: Context, deviceId: String, on: Boolean) {
viewModelScope.launch {
device.readCapability(Switch)?.let { switch ->
if (on) {
switch.on()
} else {
switch.off()
}
}
}
}
}
@Singleton
class HomeRepositoryImpl @Inject constructor(
@ApplicationContext private val context: Context
) : HomeRepository {
override fun getHomeClient(): HomeClient = Matter.getClient(context)
}
Location APIs
Get a List of Locations and Rooms
Begin by creating a MatterClient
instance:
val matterClient = Matter.getClient(context)
Get a list of locations:
val locations = matterClient.getLocations()
Get a list of rooms:
matterClient.getLocations().collect { locations ->
locations.forEach { location ->
launch {
location.getRooms().collect { rooms ->
Timber.d("Rooms:$location:$rooms")
}
}
}
}
Get a list of devices:
matterClient.getLocations().collect { locations ->
locations.forEach { location ->
launch {
location.getRooms().collect { rooms ->
rooms.forEach { room ->
launch {
room.getDevices().collect { devices ->
Timber.d("Devices:$devices")
}
}
}
}
}
}
}
Full code:
@HiltViewModel
class MainViewModel : ViewModel() {
private val _locationInfos = MutableStateFlow<List<LocationInfo>>(emptyList())
init {
viewModelScope.launch {
homeRepository.getHomeClient().getLocations().collect { locations ->
_locationInfos.value = locations.map {
LocationInfo(LocationRoomItem(it.locationName, it.locationId), emptyList())
}
locations.forEach { location ->
launch {
location.getRooms().collect { rooms ->
_locationInfos.update { locationInfos ->
locationInfos.firstOrNull { it.location.id == location.locationId }?.roomInfos =
rooms.map {
RoomInfo(
LocationRoomItem(it.roomName, it.roomId),
emptyList()
)
}
locationInfos
}
rooms.forEach { room ->
launch {
room.getDevices().collect { devices ->
_locationInfos.update { locationInfos ->
locationInfos.firstOrNull {
it.location.id == location.locationId
}?.roomInfos?.firstOrNull {
it.room.id == room.roomId
}?.devices = devices.map { device ->
DeviceItem(
device = device,
deviceActionType = getActionType(device),
onOff = getOnOffStateFlow(device),
getDrawableByDeviceType(device.getDeviceType())
)
}
locationInfos
}
}
}
}
}
}
}
}
}
}
}
Observing State Changes
The Home APIs allow observing changes to locations, rooms and device state. Observing changes in device state is possible using the Kotlin flows.
The Home APIs provide StateFlow
that can be used to collect changes to the data that is exposed by the API. This is done by collecting from that flow.
When any item in one of those collections is added, deleted, or modified, the latest snapshot of the collection is returned.
Collecting From a Flow
Collect changes to a location, including:
- Location name
- Location ID:
matterClient.getLocations().collect { locations ->
locations.forEach { location ->
Timber.d("location = name:${location.locationName}")
Timber.d("location = id:${location.locationId}")
}
}
Collect changes to a room, including:
- Room name
- Room ID
matterClient.getLocations().collect { locations ->
locations.forEach { location ->
launch {
location.getRooms().collect { rooms ->
rooms.forEach { room ->
Timber.d("room = name:${room.roomName}")
Timber.d("room = id:${room.roomId}")
}
}
}
}
}
Collect changes to devices, including:
- Device name
- Device ID
- Location ID
- Room ID
matterClient.getLocations().collect { locations ->
locations.forEach { location ->
launch {
location.getRooms().collect { rooms ->
rooms.forEach { room ->
launch {
room.getDevices().collect { devices ->
devices.forEach { device ->
Timber.d("device = name:${device.deviceName}")
Timber.d("device = id:${device.deviceId}")
Timber.d("device = locationId:${device.locationId}")
Timber.d("device = roomId:${device.roomId}")
}
}
}
}
}
}
}
}