Structure API는 Android용 Home API를 통해 액세스할 수 있습니다. 이러한 패키지를 앱으로 가져옵니다.
import com.google.home.Home
import com.google.home.Id
import com.google.home.Structure
오류 처리
Home API의 모든 메서드는
HomeException를 발생시킬 수 있으므로 try-catch 블록을 사용하여 모든 호출에서 HomeException를 포착하는 것이 좋습니다.
HomeException를 처리할 때
error.code 및
error.message 필드를 확인하여 무엇이 잘못되었는지 확인합니다. 하위 오류 코드도 있을 수 있으므로
getSubErrorCodes() 메서드를 호출하고 결과를 확인합니다.
처리되지 않은 예외가 있으면 앱이 비정상 종료됩니다.
자세한 내용은 오류 처리를 참고하세요.
샘플 호출
구조 목록 가져오기
초기화되면 structures() 호출은 액세스할 수 있는 구조의 Flow를 반환합니다.
// Get a flow of all structures accessible to the user val allStructuresFlow: HomeObjectsFlow<Structure> = home.structures() // Calling list() on a HomeObjectsFlow returns the first Set of elements. val allStructures: Set<Structure> = allStructuresFlow.list()
structures() API는 유효한 구조 목록을 즉시 반환하지 않을 수 있는 흐름입니다. 앱이 반응형이고 UI를 구동하기 위해 해당 흐름을 구독하는 경우 유효한 구조 목록이 최종적으로 반환되어야 합니다.
사용자의 휴대전화가 연결이 끊어지거나 사용자가 앱에 대한 권한을 취소한 경우와 같이 빈 구조 목록이 반환될 수 있는 다른 상황이 있습니다. 앱에서 이러한 사례를 처리해야 합니다.
또는 반응형 프로그래밍 대신 명령형 프로그래밍이 강력하게 요구되는 경우 터미널 흐름 연산자를 사용할 수 있습니다.
val everyStructure = withTimeout(5000) { home.structures().first { it.isNotEmpty() } }
이 호출은 유효한 구조 목록이 흐름을 통해 전달될 때까지 기다리며, 앱에서 지정한 제한 시간 내에 목록이 수신되지 않으면 제한 시간이 초과됩니다.
구조 속성 가져오기
구조 목록을 확보하면 해당 구조의 속성에 액세스할 수 있습니다.
// Get a flow on a structure. Flow emits new values on structure metadata changes: name. val structureFlow: Flow<Structure> = home.structures().itemFlow(myStructureId) // Get a snapshot of the structure. val structure: Structure = structureFlow.first() // Get structure properties println("id ${structure.id}") println("name ${structure.name}")
이름으로 구조물 찾기
구조의 이름을 알고 있는 경우 name 속성을 사용하여 액세스할 수도 있습니다.
val myHome = home.structures().list().first { it.name == "My home" }
여기에서 각 집의 속성, 방, 기기에 액세스할 수 있습니다.
여러 집 사용하기
구조를 두 개 이상 사용하려면 각 구조에 대한 별도의 참조를 가져옵니다.
var structure1: Structure? = null var structure2: Structure? = null try { structure1 = home.structures().list().firstOrNull { it.name == "Main House" } } catch (e: HomeException) { // Code for handling the exception } try { structure2 = home.structures().list().firstOrNull { it.name == "Guest Cottage" } } catch (e: HomeException) { // Code for handling the exception }
채팅방 목록 가져오기
구조가 있으면 방 목록을 가져오고 속성에 액세스할 수 있습니다.
val allRoomsFlow: HomeObjectsFlow<Room> = structure.rooms() val allRooms: Set<Room> = allRoomsFlow.list() val room: Room = allRooms.first() println("id ${room.id}") println("name ${room.name}")
채팅방 만들기
새 채팅방을 만들려면 다음 단계를 따르세요.
val testName = "Test Room Name" val newRoom: Room = structure.createRoom(testName)
방 삭제하기
또는 다음과 같이 채팅방을 삭제할 수 있습니다.
val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull() structure.deleteRoom(roomToDelete!!)
ID만으로 채팅방을 삭제할 수도 있습니다.
val roomToDelete1 = allRooms.filter { it.id == testRoomId }.firstOrNull() structure.deleteRoom(roomToDelete1!!)
기기가 있는 방이 삭제되면 기기는 여전히 구조에 있지만 더 이상 방에 할당되지 않습니다.
다른 방으로 기기 이동하기
구조가 있으면 해당 구조 내의 다른 방으로 기기를 이동할 수 있습니다.
val room2 = structure.rooms().get(Id("room_id_other_structure")) val device1 = structure.devices().get(Id("device_id1")) structure.moveDevicesToRoom(room2!!, listOf(device1!!))
기기 및 회의실 ID만 있는 경우 다음과 같이 기기를 이동할 수도 있습니다.
structure.moveDevicesToRoom(Id("room_id_other_structure"), listOf(Id("device_id1")))
방 이름 변경하기
setName() 메서드를 호출하여 방 이름을 변경합니다.
livingRoom.setName("Living Room")
이름이 유니코드 코드 포인트(문자) 한도인 60자를 초과하면 잘리고 오류가 발생하지 않습니다. 개발자는 긴 이름을 처리할 책임이 있으며, 예를 들어 이름이 잘린다는 사실을 사용자에게 알릴지 여부를 결정할 수 있습니다.
사용자가 권한을 부여한 기기 유형 보기
Google Home 생태계에서 대부분의 기기 유형의 경우 사용자는 해당 유형의 모든 기기에 대한 권한을 한 번에 부여할 수 있습니다. 도어락, 카메라, 초인종과 같은 민감하거나 제한된 기기 유형의 경우 사용자가 개별적으로 권한을 부여해야 합니다.
사용자가 민감한 기기 유형 또는 제한된 기기 유형에 액세스할 수 있는 권한을 부여했는지 확인하려면 구조 수준 consentedDeviceTypes() 함수를 사용하세요.
import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/**
* Example of how an app may monitor which device types have been granted access by a user.
*/
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
// Obtain the flow of consented device type factories
val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
structure.consentedDeviceTypes()
myScope.launch {
consentedTypesFlow.collect { consentedSet ->
// Check if the user has consented to share a specific restricted
// type, such as a Doorbell or Camera.
val hasCameraAccess = consentedSet.any {
it.toString() == "matter.google.type.GoogleDoorbellDevice"
}
if (hasCameraAccess) {
// Enable features that require camera access
} else {
// Inform the user or disable camera-specific features
}
}
}
}
기기 그룹
기기 그룹은 단일 구조 내에서 사용자가 정의한 기기 모음을 나타냅니다. 그룹 멤버십은 Google 서비스에 유지되며 구조의 다른 구성원과 구조에 액세스할 수 있는 다른 앱에 표시됩니다.
실제 방과 마찬가지로 기기 그룹은 단일 구조에 속합니다. 하지만 방과 달리 기기 그룹은 논리적 그룹입니다. 기기는 동시에 여러 기기 그룹에 속할 수 있습니다. 기기 그룹에는 최대 100개의 기기가 포함될 수 있습니다.
기기 그룹은DeviceGroup 항목으로 표현되며, 이는 HomeDevice와 다릅니다. 기기 그룹을 쿼리하고 상호작용하려면 FactoryRegistry를 초기화할 때 entityTypes 목록에 DeviceGroup를 Group, GroupManagement, GroupMembership 특성과 함께 포함합니다.
그룹의 기기와 상호작용하려면 구성원 기기를 직접 반복하거나 (그룹 구성원 기기와 상호작용 참고) DeviceGroup에서 기기 유형 부분을 타겟팅하면 됩니다 (기기 그룹 제어 참고).
기기 그룹 목록 가져오기
구조의 모든 기기 그룹을 관찰하려면 home.entities(DeviceGroup)를 호출하고 구조의 ID로 필터링합니다.
home.entities(DeviceGroup).collect { allGroups ->
val structureGroups = allGroups.filter { it.structureId == structure.id }
for (group in structureGroups) {
val groupName = group.trait(Group)?.Name
println("Found group: $groupName with ID: ${group.id.id}")
}
}
그룹 구성원 기기와 상호작용
group.devices()를 사용하여 그룹의 구성원 기기를 반복하면 개별 구성원을 세밀하게 제어하고, 단일 요청에서 명령어를 일괄 처리하고, 구성원 간에 속성을 집계하거나 작성할 수 있습니다.
예를 들어 그룹의 모든 호환 구성원에 걸쳐 특성에 대한 명령어가 포함된 단일 일괄 요청을 전송하려면 다음을 실행합니다.
val members = group.devices(enableMultipartDevices = true).first()
val onOffTraits = members.mapNotNull { device ->
device.partOrNull(OnOffLightDevice).first()?.standardTraits?.onOff
}
val responses = home.sendBatchedCommands {
onOffTraits.map { onOff ->
add(onOff.onBatchable())
}
}
for (response in responses) {
response.getOrThrow()
}
그룹의 모든 일치하는 구성원 기기에서 속성을 업데이트하고(예: 모든 DimmableLightDevice 구성원에서 onTransitionTime를 1u로 설정) 기한 내에 완료될 때까지 기다릴 수도 있습니다.
val members = group.devices(enableMultipartDevices = true).first()
withTimeout(5.seconds) {
members.map { device ->
async {
val light = device.partOrNull(DimmableLightDevice).first()
val levelControl = light?.standardTraits?.levelControl
if (
levelControl?.supports(
LevelControl.Attribute.onTransitionTime
) == true
) {
levelControl.update { setOnTransitionTime(1u) }
}
}
}.awaitAll()
}
그룹의 모든 색상 온도 조명에서 최소 colorTempPhysicalMaxMireds를 찾는 것과 같이 그룹 구성원 전체의 속성을 집계하려면 다음을 실행합니다.
val members = group.devices(enableMultipartDevices = true).first()
val minMaxMireds: UShort? = members.mapNotNull { device ->
val light = device.partOrNull(ColorTemperatureLightDevice).first()
light?.standardTraits?.colorControl?.colorTempPhysicalMaxMireds
}.minOrNull()
기기 그룹 만들기
구조에서 GroupManagement를 사용하여 기기 그룹을 만듭니다.
val groupManagement = structure.trait(GroupManagementTrait)
val response = groupManagement?.createUserDefinedGroup(
name = "Living room lights",
memberDeviceObjectIds = listOf(light1.id.id, light2.id.id)
)
그룹 멤버십 관리하기
기존 그룹에 구성원을 추가하려면 다음 안내를 따르세요.
structure.trait(GroupManagementTrait)?.addGroupMembers(
groupObjectId = group.id.id,
memberDeviceObjectIds = listOf(light3.id.id)
)
그룹에서 회원을 삭제하려면 다음 단계를 따르세요.
structure.trait(GroupManagementTrait)?.removeGroupMembers(
groupObjectId = group.id.id,
memberDeviceObjectIds = listOf(light1.id.id)
)
기기 그룹 이름 변경하기
기기 그룹의 이름을 바꾸려면 그룹의 GroupTrait에서 이름 속성을 업데이트합니다.
group.trait(GroupTrait)?.update {
name = "Movie corner"
}
기기 그룹 삭제
집에서 기기 그룹을 삭제하려면 다음 단계를 따르세요.
structure.trait(GroupManagementTrait)?.deleteGroup(
groupObjectId = group.id.id
)
자동화
Automation API의 진입점은 구조를 통해 이루어집니다. Home API의 자동화에 대해 자세히 알아보려면 Android의 Automation API 개요를 참고하세요.