1. Trước khi bắt đầu
Google Home API cung cấp một bộ thư viện để nhà phát triển Android khai thác hệ sinh thái Google Home. Với các API mới này, nhà phát triển có thể tạo các ứng dụng giúp dễ dàng thiết lập và điều khiển các thiết bị nhà thông minh.
Google cung cấp một Ứng dụng mẫu Android cho những nhà phát triển muốn truy cập vào một ví dụ hoạt động bằng cách sử dụng Google Home API. Lớp học lập trình này dựa trên một nhánh của Ứng dụng mẫu, hướng dẫn bạn cách sử dụng các API Quyền, Thiết lập, Thiết bị và Cấu trúc.
Điều kiện tiên quyết
- Có kiến thức về hệ sinh thái Google Home (Cloud-to-cloud và Matter).
- Một máy trạm đã cài đặt Android Studio (2024.3.1 Ladybug trở lên).
- Điện thoại Android đáp ứng các yêu cầu về Home API (xem phần Điều kiện tiên quyết) đã cài đặt Dịch vụ Google Play và Ứng dụng Google Home.
- Một Google Home Hub tương thích và hỗ trợ API Google Home.
- Không bắt buộc – Thiết bị nhà thông minh tương thích với Google Home API.
Kiến thức bạn sẽ học được
- Cách tạo ứng dụng Android bằng Google Home API theo các phương pháp hay nhất.
- Cách sử dụng API Thiết bị và API Cấu trúc để thể hiện và điều khiển một ngôi nhà thông minh.
- Cách sử dụng Commissioning API để thêm thiết bị vào hệ sinh thái Google Home.
Không bắt buộc: Thiết lập nhà của bạn
Trước khi sử dụng Google Home API, bạn cần thiết lập một nhà trên Tài khoản Google của mình bằng ứng dụng Google Home và thêm một số thiết bị. Phần này thảo luận về cách thực hiện việc này bằng Google Home Playground, nơi cung cấp các thiết bị nhà thông minh ảo.
Mở home-playground.withgoogle.com trong trình duyệt web, đăng nhập bằng Tài khoản Google của bạn và xem các thiết bị mô phỏng sau đây có xuất hiện hay không:
- outlet1: Ổ cắm bật/tắt
- light2: Đèn có thể điều chỉnh độ sáng
- light3: Bật/Tắt đèn
- ac3: Điều hoà không khí
- blinds4: Mành che cửa sổ
- washer5: Máy giặt thông minh
Mở ứng dụng Google Home trên thiết bị di động, nhấn vào nút Thêm rồi chọn Hoạt động với Google Home. Tìm "playground" trong danh sách, sau đó chọn dự án "Google Home Playground" rồi nhấn vào Tiếp tục.
Google Home Playground sẽ cho bạn thấy trang uỷ quyền tài khoản. Nhấn vào Uỷ quyền hoặc Đăng nhập bằng Google. Bạn sẽ thấy tất cả các thiết bị mà bạn đã định cấu hình trong ứng dụng di động thông qua ứng dụng web.
Chọn tất cả các thiết bị rồi hoàn tất quy trình thiết lập. Khi quay lại Trang chủ, bạn sẽ thấy tất cả các thiết bị có sẵn.
Giờ đây, bạn có thể sử dụng các thiết bị được hỗ trợ trong danh sách với Google Home API.
2. Thiết lập dự án
Sơ đồ sau đây minh hoạ cấu trúc của một ứng dụng Home API:
- Mã ứng dụng: Mã cốt lõi mà nhà phát triển sử dụng để tạo giao diện người dùng của ứng dụng và logic tương tác với Home APIs SDK.
- Home APIs SDK: Home APIs SDK do Google cung cấp hoạt động với Dịch vụ Home APIs trong GMSCore để điều khiển các thiết bị nhà thông minh. Nhà phát triển tạo các ứng dụng hoạt động với Home API bằng cách kết hợp các ứng dụng đó với Home API SDK.
- GMSCore trên Android: GMSCore (còn gọi là Dịch vụ Google Play) là một nền tảng của Google cung cấp các dịch vụ hệ thống cốt lõi, cho phép các chức năng chính hoạt động trên mọi thiết bị Android được chứng nhận. Mô-đun trang chủ của Dịch vụ Google Play chứa các dịch vụ tương tác với Home API.
Thiết lập Home SDK
Hãy làm theo các bước được nêu trong phần Thiết lập SDK để tải SDK mới nhất.
Tải ứng dụng mẫu
Mã nguồn cho Ứng dụng mẫu có trên GitHub. Lớp học lập trình này sử dụng các ví dụ trong nhánh codelab-branch-1
của Ứng dụng mẫu.
Chuyển đến vị trí bạn muốn lưu dự án và sao chép nhánh codelab-branch-1
:
$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git
Tạo ứng dụng mẫu
Thực hiện các bước 1 đến 5 trong phần Tạo ứng dụng.
Khi ứng dụng chạy thành công trên điện thoại, bạn sẽ thấy trang chính của Ứng dụng mẫu. Tuy nhiên, bạn sẽ không thể đăng nhập cho đến khi thiết lập quy trình xác thực OAuth và triển khai các phần còn thiếu bằng Permission API.
3. Thiết lập tính năng xác thực
Home API sử dụng OAuth 2.0 để cấp quyền truy cập vào các thiết bị trong cấu trúc. OAuth cho phép người dùng cấp quyền cho một ứng dụng hoặc dịch vụ mà không cần tiết lộ thông tin đăng nhập của họ.
Làm theo hướng dẫn trong phần Thiết lập sự đồng ý OAuth để định cấu hình màn hình đồng ý. Hãy nhớ tạo ít nhất một tài khoản kiểm thử.
Sau đó, hãy làm theo hướng dẫn trong phần Thiết lập thông tin đăng nhập OAuth để tạo thông tin đăng nhập cho ứng dụng.
4. Khởi tạo và xử lý quyền
Trong phần này, bạn sẽ tìm hiểu cách khởi chạy SDK và xử lý quyền của người dùng bằng cách hoàn tất các phần còn thiếu bằng Permissions API.
Xác định các loại và đặc điểm được hỗ trợ
Khi phát triển một ứng dụng, bạn cần ghi chú rõ ràng những loại thiết bị và đặc điểm mà ứng dụng sẽ hỗ trợ. Trong Ứng dụng mẫu, chúng ta thực hiện việc này bằng cách xác định các danh sách tĩnh trong đối tượng companion trong HomeApp.kt
. Sau đó, bạn có thể tham chiếu các danh sách này trong toàn bộ ứng dụng khi cần:
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
OnOffLightDevice,
DimmableLightDevice,
// ...
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
OnOff,
LevelControl,
// ...
)
}
Hãy xem Các loại thiết bị được hỗ trợ và Chỉ mục đặc điểm trên Android để xem tất cả các loại thiết bị và đặc điểm được hỗ trợ.
Huỷ chú thích các Bước 4.1.1 và 4.1.2 trong tệp nguồn HomeApp.kt
để bật mã nguồn yêu cầu quyền.
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
// ContactSensorDevice,
// ColorTemperatureLightDevice,
// DimmableLightDevice,
// ExtendedColorLightDevice,
// GenericSwitchDevice,
// GoogleDisplayDevice,
// GoogleTVDevice,
// OccupancySensorDevice,
// OnOffLightDevice,
// OnOffLightSwitchDevice,
// OnOffPluginUnitDevice,
// OnOffSensorDevice,
// RootNodeDevice,
// SpeakerDevice,
// ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
// AreaAttendanceState,
// AreaPresenceState,
// Assistant,
// AssistantBroadcast,
// AssistantFulfillment,
// BasicInformation,
// BooleanState,
// OccupancySensing,
// OnOff,
// Notification,
// LevelControl,
// TemperatureControl,
// TemperatureMeasurement,
// Thermostat,
// Time,
// Volume,
)
}
Khởi động đối tượng HomeClient
Tất cả ứng dụng sử dụng Home API đều khởi chạy một đối tượng HomeClient
. Đây là giao diện chính để tương tác với các API. Chúng ta chuẩn bị đối tượng này trong trình khởi tạo của lớp HomeApp
(HomeApp.kt
).
// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
types = supportedTypes,
traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
coroutineContext = Dispatchers.IO,
factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)
Trước tiên, chúng ta sẽ tạo một FactoryRegistry
bằng cách sử dụng các loại và đặc điểm được hỗ trợ mà chúng ta đã xác định trước đó. Sau đó, bằng cách sử dụng sổ đăng ký này, chúng ta sẽ khởi động HomeConfig
. Sổ đăng ký này chứa cấu hình cần thiết để chạy các API. Tiếp theo, chúng ta sử dụng lệnh gọi Home.getClient(...)
để lấy thực thể HomeClient
.
Mọi hoạt động tương tác của chúng ta với Home API đều sẽ thông qua đối tượng HomeClient
này.
Sử dụng Permissions API
Việc xác thực người dùng cho Home API được thực hiện thông qua Permissions API. Tệp nguồn PermissionsManager.kt
của Ứng dụng mẫu chứa mã để xác thực người dùng. Huỷ đánh dấu nội dung của các hàm checkPermissions(...)
và requestPermissions(...)
để bật các quyền cho Ứng dụng mẫu.
Đang đăng ký:
homeClient.registerActivityResultCallerForPermissions(activity)
Ra mắt:
try {
val result: PermissionsResult
result = homeClient.requestPermissions(forceLaunch = true)
when (result.status) {
PermissionsResultStatus.SUCCESS -> // Success Case
PermissionsResultStatus.CANCELLED -> // User Cancelled
PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
}
}
catch (e: HomeException) { ... }
Kiểm tra:
try {
val state: PermissionsState
state = homeClient.hasPermissions().first { state ->
state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
}
when (state) {
PermissionsState.GRANTED -> // Signed In
PermissionsState.NOT_GRANTED -> // Not Signed In
PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
}
}
catch (e: HomeException) { ... }
Đăng ký:
homeClient.hasPermissions().collect( { state ->
// Track the changes on state
} )
Huỷ đánh dấu bình luận Bước 4.3.1 trong PermissionsManager.kt
để bật mã yêu cầu cấp quyền:
fun requestPermissions() {
scope.launch {
try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
// // Request permissions from the Permissions API and record the result:
// val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
// // Adjust the sign-in status according to permission result:
// if (result.status == PermissionsResultStatus.SUCCESS)
// isSignedIn.emit(true)
// // Report the permission result:
// reportPermissionResult(result)
}
catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
}
}
Bây giờ, hãy chạy ứng dụng trên điện thoại, làm theo các bước và cho phép các quyền. Bạn sẽ thấy quy trình sau:
Thông báo "Đang tải" không bao giờ biến mất, nhưng điều này là do chúng tôi chưa triển khai mã đọc cấu trúc và thiết bị. Chúng ta sẽ làm việc đó trong phần tiếp theo.
5. Tìm hiểu về mô hình dữ liệu
Trong Home API, Mô hình dữ liệu bao gồm:
Structure
đại diện cho một nhà có các phòng và thiết bị.Room
là một phần của cấu trúc và chứa các thiết bị.- Bạn có thể chỉ định thiết bị (được xác định là
HomeDevice
) cho một cấu trúc (hoặc nhà) hoặc một phòng trong cấu trúc. - Thiết bị bao gồm một hoặc nhiều phiên bản
DeviceType
. DeviceType
bao gồm các phiên bảnTrait
.Trait
bao gồm các thực thểAttribute
(để đọc/ghi), các thực thểCommand
(để kiểm soát các thuộc tính) và các thực thểEvent
(để đọc hoặc đăng ký các bản ghi về những thay đổi trước đây).- Các thực thể
Automation
là một phần của cấu trúc và sử dụng siêu dữ liệu cũng như thiết bị trong nhà để tự động hoá các tác vụ trong nhà.
Trong phần này, bạn sẽ tìm hiểu cách phát triển mã nguồn để cho biết cách sử dụng API cấu trúc nhằm phân tích cú pháp và hiển thị các cấu trúc nhà, phòng, thiết bị, v.v.
Đọc cấu trúc
Thiết kế Home API dựa trên Kotlin Flow để truyền trực tuyến các đối tượng mô hình dữ liệu (ví dụ: Structure
, HomeDevice
, v.v.). Nhà phát triển đăng ký Flow
để nhận tất cả các đối tượng có trong đối tượng (ví dụ: Structure
, Room
, v.v.).
Để truy xuất tất cả các cấu trúc, hãy gọi hàm structures()
. Hàm này sẽ trả về một luồng cấu trúc. Sau đó, hãy gọi hàm danh sách trên luồng để lấy tất cả các cấu trúc mà người dùng sở hữu.
// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
homeClient.structures() // HomeObjectsFlow<Structure>
.list() // Set<Structure>
Hướng dẫn về cấu trúc ứng dụng đặc biệt khuyến khích bạn áp dụng phương pháp Lập trình phản ứng hiện đại để cải thiện luồng dữ liệu và hoạt động quản lý trạng thái của ứng dụng.
Sau đây là cách Ứng dụng mẫu tuân thủ kiểu lập trình Phản ứng:
- Các mô hình hiển thị (chẳng hạn như
StructureViewModel
vàDeviceViewModel
, dưới dạng phần tử giữ trạng thái) đăng ký các luồng từ Home APIs SDK để nhận các thay đổi về giá trị và duy trì trạng thái mới nhất. - Các thành phần hiển thị (chẳng hạn như
StructureView
vàDeviceView
) đăng ký các mô hình hiển thị để nhận trạng thái và kết xuất giao diện người dùng nhằm phản ánh những thay đổi đó. - Khi người dùng nhấp vào một nút trên chế độ xem (ví dụ: nút "Bật" của thiết bị chiếu sáng), các sự kiện sẽ kích hoạt các hàm của mô hình chế độ xem, gọi các hàm Home API phản hồi (ví dụ: lệnh
On
của đặc điểmOnOff
).
Trong Bước 5.1.1 trong HomeAppViewModel.kt
, chúng ta đăng ký nhận các sự kiện thay đổi cấu trúc bằng cách gọi hàm collect()
. Huỷ đánh dấu phần duyệt qua structureSet
do phản hồi Structures API trả về và được phân phối trong StructureViewModel's
StateFlow
. Điều này cho phép ứng dụng theo dõi các thay đổi về trạng thái cấu trúc:
private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
// val structureVMList: MutableList<StructureViewModel> = mutableListOf()
// // Store structures in container ViewModels:
// for (structure in structureSet) {
// structureVMList.add(StructureViewModel(structure))
// }
// // Store the ViewModels:
// structureVMs.emit(structureVMList)
//
// // If a structure isn't selected yet, select the first structure from the list:
// if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
// selectedStructureVM.emit(structureVMList.first())
//
// }
}
Trong DevicesView.kt
, ứng dụng đăng ký StructureViewModel'sStateFlow,
để kích hoạt quá trình kết hợp lại giao diện người dùng khi dữ liệu cấu trúc thay đổi. Huỷ đánh dấu mã nguồn trong Bước 5.1.2 để hiển thị danh sách cấu trúc dưới dạng trình đơn thả xuống:
val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
// for (structure in structureVMs) {
// DropdownMenuItem(
// text = { Text(structure.name) },
// onClick = {
// scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
// expanded = false
// }
// )
// }
}
...
Chạy lại ứng dụng. Bạn sẽ thấy trình đơn khi nhấn vào mũi tên:
Phân tích cú pháp cấu trúc
Bước tiếp theo là di chuyển các đối tượng nhà trong một cấu trúc. Truy xuất các phòng từ cấu trúc:
val rooms: Set<Room>
rooms = structure.rooms().list()
Sau đó, bạn có thể duyệt qua các phòng để truy xuất thiết bị:
val devices: Set<HomeDevice>
devices = room.devices().list()
Lưu ý quan trọng: Trong mô hình dữ liệu Home APIs, một cấu trúc có thể chứa các thiết bị chưa được chỉ định cho một phòng, vì vậy, hãy nhớ thu thập cả những thiết bị không có phòng trong ứng dụng của bạn:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (device.roomId == null)
devicesWithoutRooms.add(device)
Một lần nữa, trong mã mẫu hiện có, chúng ta đăng ký một luồng để nhận danh sách Phòng và Thiết bị mới nhất. Kiểm tra mã ở Bước 5.2.1 và 5.2.2 trong tệp nguồn StructureViewModel.kt
rồi xoá dấu chú thích để bật tính năng đăng ký dữ liệu phòng:
val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
// // Subscribe to changes on rooms:
// structure.rooms().collect { roomSet ->
// val roomVMs = mutableListOf<RoomViewModel>()
// // Store rooms in container ViewModels:
// for (room in roomSet) {
// roomVMs.add(RoomViewModel(room))
// }
// // Store the ViewModels:
// this.roomVMs.emit(roomVMs)
// }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
// // Subscribe to changes on devices:
// structure.devices().collect { deviceSet ->
// val deviceVMs = mutableListOf<DeviceViewModel>()
// val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
// // Store devices in container ViewModels:
// for (device in deviceSet) {
// val deviceVM = DeviceViewModel(device)
// deviceVMs.add(deviceVM)
// // For any device that's not in a room, additionally keep track of a separate list:
// if (device.roomId == null)
// deviceWithoutRoomVMs.add(deviceVM)
// }
// // Store the ViewModels:
// this.deviceVMs.emit(deviceVMs)
// deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
// }
}
Huỷ đánh dấu là chú thích cho các bước 5.2.3 và 5.2.4 trong tệp nguồn DevicesView.kt
để hiển thị danh sách phòng dưới dạng một trình đơn:
val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
// RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
// val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
// for (deviceVM in deviceVMsInRoom) {
// DeviceListItem(deviceVM, homeAppVM)
// }
}
Giờ đây, khi đã có các thiết bị, chúng ta sẽ tìm hiểu cách sử dụng chúng.
6. Làm việc với các thiết bị
Home API sử dụng đối tượng HomeDevice
để ghi lại thiết bị và các chức năng của thiết bị. Nhà phát triển có thể đăng ký nhận thông tin về các thuộc tính của thiết bị và sử dụng các thuộc tính đó để thể hiện thiết bị nhà thông minh trong ứng dụng của họ.
Đọc trạng thái thiết bị
Đối tượng HomeDevice
trình bày một tập hợp các giá trị tĩnh, chẳng hạn như tên thiết bị hoặc trạng thái kết nối. Là nhà phát triển, bạn có thể truy xuất những thông tin này ngay sau khi nhận được thiết bị từ API:
val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
device.sourceConnectivity.connectivityState
Để biết các chức năng của thiết bị, bạn cần truy xuất các loại và đặc điểm từ HomeDevice
. Để làm việc này, bạn có thể đăng ký luồng loại thiết bị như sau và truy xuất các đặc điểm từ các loại thiết bị:
device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
primaryType = typeInSet
val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
traits.add(trait)
for (trait in traits)
parseTrait(trait, primaryType)
}
Mỗi thiết bị đều chứa một nhóm DeviceType
được hỗ trợ (các chức năng đi kèm) mà bạn có thể truy xuất bằng device.types()
. Các loại thiết bị này có những đặc điểm mà bạn có thể truy xuất bằng type.traits()
. Mỗi thiết bị đánh dấu một trong các loại của thiết bị đó là loại chính (bạn có thể kiểm tra bằng cách sử dụng type.metadata.isPrimaryType
) mà bạn nên thể hiện trong ứng dụng của mình. Để mang lại trải nghiệm hoàn chỉnh cho người dùng, bạn nên duyệt qua tất cả các loại được trả về và tích hợp tất cả các đặc điểm có sẵn cho bạn.
Sau khi truy xuất một đặc điểm, bạn có thể phân tích cú pháp đặc điểm đó bằng một hàm như sau để diễn giải các giá trị:
fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
val status : String = when (trait) {
is OnOff -> { if (trait.onOff) "On" else "Off" }
is LevelControl -> { trait.currentLevel.toString() }
is BooleanState -> {
when (type.factory) {
ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
}
else -> ...
}
}
else -> ...
}
}
Xin lưu ý rằng có thể có sự khác biệt về ý nghĩa của một đặc điểm, tuỳ thuộc vào loại thiết bị có đặc điểm đó (xem BooleanState
trong ví dụ trước). Vì vậy, bạn cần nắm được bối cảnh của từng loại thiết bị để hiểu rõ ý nghĩa thực sự của các đặc điểm.
Huỷ đánh dấu là chú thích cho các bước 6.1.1 và 6.1.2 trong tệp nguồn DeviceViewModel.kt
để truy xuất các trạng thái:
private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
// // Among all the types returned for this device, find the primary one:
// for (typeInSet in typeSet)
// if (typeInSet.metadata.isPrimaryType)
// primaryType = typeInSet
//
// // Optional: For devices with a single type that did not define a primary:
// if (primaryType is UnknownDeviceType && typeSet.size == 1)
// primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
// for (trait in traits)
// if (trait.factory in HomeApp.supportedTraits)
// supportedTraits.add(trait)
return supportedTraits
}
Huỷ nhận xét Bước 6.1.3 trong DeviceView.kt
để hiển thị một đặc điểm OnOff, bao gồm cả tên và trạng thái của đặc điểm đó, dưới dạng String
:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
// Text(trait.factory.toString(), fontSize = 20.sp)
// Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
...
}
is BooleanState -> {
...
}
is OccupancySensing -> {
...
}
...
}
Nếu bạn chạy ứng dụng ngay bây giờ với các loại thiết bị được hỗ trợ (ví dụ: thiết bị chiếu sáng), thì ứng dụng sẽ cho thấy trạng thái mới nhất của tất cả các thiết bị.
Ra lệnh cho thiết bị
Để đưa ra lệnh cho các thiết bị, Home API cung cấp các hàm tiện lợi trên các đối tượng Đặc điểm như trait.on()
hoặc trait.moveToLevel(...)
:
fun <T : Trait?> issueCommand(trait : T) {
when (trait) {
is OnOff -> {
// trait.on()
// trait.off()
}
is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
}
}
}
Lưu ý: Sau khi xác định loại đặc điểm, hãy sử dụng tính năng tự động hoàn thành của Android Studio để xem những loại thao tác có thể tương tác với đặc điểm.
Huỷ đánh dấu phần Bước 6.2.1 trong DeviceView.kt
để thêm các chế độ kiểm soát chức năng vào ứng dụng:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
....
// TODO: 6.2.1 - Render controls based on the trait type
// Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
// onCheckedChange = { state ->
// scope.launch { if (state) trait.on() else trait.off() }
// },
// enabled = isConnected
// )
}
Nếu chạy ứng dụng ngay bây giờ, bạn có thể điều khiển các thiết bị thực trong đời thực.
Nếu bạn nhấn vào nút điều khiển Bật/tắt trên bóng đèn, thì thiết bị sẽ bật.
Để biết thêm thông tin về cách điều khiển thiết bị, hãy xem bài viết Điều khiển thiết bị trên Android.
7. Uỷ quyền thiết bị
Commissioning API cho phép nhà phát triển thêm thiết bị vào hệ sinh thái Google Home và cho phép người dùng điều khiển các thiết bị đó bằng Home API. Chỉ các thiết bị Matter được hỗ trợ. Trong phần này, chúng ta sẽ khám phá cách bật tính năng thiết lập thiết bị trong các ứng dụng của bạn.
Trước khi bắt đầu phần này, hãy đảm bảo bạn đáp ứng các điều kiện tiên quyết sau:
- Một Google Hub hỗ trợ Matter nằm trong cùng mạng với điện thoại Android của bạn đã được thêm vào ứng dụng Google Home.
- Bạn đã tạo một dự án nhà phát triển trên Google Home Developer Console bằng VID
0xFFF1
và PID0x8000
.
Nếu có một thiết bị Matter thực tế có mã QR để thiết lập, bạn có thể chuyển sang bước Bật API thiết lập. Nếu không, hãy tiếp tục chuyển sang phần tiếp theo, nơi chúng ta sẽ thảo luận về cách bạn có thể sử dụng ứng dụng Thiết bị ảo Matter (MVD) để tạo các thiết bị ảo có thể thiết lập.
Không bắt buộc: Chuẩn bị một thiết bị có thể thiết lập theo chuẩn Matter
Cách đơn giản nhất để chuẩn bị một thiết bị có thể thiết lập Matter là sử dụng thiết bị mô phỏng do ứng dụng Thiết bị ảo Matter (MVD) cung cấp.
Sau khi cài đặt MVD và thiết lập tường lửa, hãy chạy MVD:
Tạo một thiết bị OnOff. Lưu ý rằng thiết bị này chưa được đưa vào sử dụng – bạn sẽ đưa thiết bị vào sử dụng sau trong lớp học lập trình này.
Bật API thiết lập
Commissioning API hoạt động bên ngoài Hoạt động của ứng dụng, vì vậy, bạn cần xử lý quy trình thiết lập theo cách khác với các Home API khác. Để chuẩn bị ứng dụng cho quá trình uỷ quyền, bạn cần có 2 biến.
Một biến là ActivityResultLauncher
, được dùng để gửi ý định thiết lập và quản lý lệnh gọi lại kết quả. Biến còn lại là CommissioningResult
, đây là đối tượng dùng để lưu trữ kết quả khởi động. Hãy xem ví dụ sau đây về cách thiết lập quy trình thiết lập:
var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
commissioningResult = CommissioningResult.fromIntentSenderResult(
result.resultCode, result.data)
} catch (exception: ApiException) {
// Catch any issues
}
}
Sau khi thiết lập quy trình thiết lập, bạn sẽ tạo ý định thiết lập và khởi chạy ý định đó bằng trình chạy mà chúng ta đã tạo trong ví dụ trước. Bạn nên đặt ý định và trình chạy trong một hàm chuyên dụng như sau. Bạn có thể liên kết một chức năng chuyên dụng với một phần tử trên giao diện người dùng (chẳng hạn như nút +Add Device (+Thêm thiết bị)) và gọi chức năng đó dựa trên yêu cầu của người dùng:
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
scope.launch {
// Create a commissioning request to store the device in Google's Fabric:
val request = CommissioningRequest.builder()
.setStoreToGoogleFabric(true)
.setOnboardingPayload(payload)
.build()
// Initialize client and sender for commissioning intent:
val client: CommissioningClient = Matter.getCommissioningClient(context)
val sender: IntentSender = client.commissionDevice(request).await()
// Launch the commissioning intent on the launcher:
launcher.launch(IntentSenderRequest.Builder(sender).build())
}
}
Huỷ đánh dấu Bước 7.1.1 trong CommissioningManager.kt
để bật khả năng thiết lập và làm cho nút +Add Device (Thêm thiết bị) hoạt động trong Ứng dụng mẫu.
// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
// // Create a commissioning request to store the device in Google's Fabric:
// val request = CommissioningRequest.builder()
// .setStoreToGoogleFabric(true)
// .setOnboardingPayload(payload)
// .build()
// // Initialize client and sender for commissioning intent:
// val client: CommissioningClient = Matter.getCommissioningClient(context)
// val sender: IntentSender = client.commissionDevice(request).await()
// // Launch the commissioning intent on the launcher:
// launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}
Khi chạy hàm này, Quy trình thiết lập sẽ bắt đầu và hiển thị một màn hình tương tự như ảnh chụp màn hình sau:
Tìm hiểu quy trình Thiết lập
Quy trình thiết lập bao gồm một bộ màn hình hướng dẫn người dùng thêm thiết bị vào Tài khoản Google của họ:
Người dùng sẽ thấy một trình quét mã QR mà họ có thể dùng để quét mã QR của các thiết bị theo chuẩn Matter. Sau đó, quy trình sẽ chuyển sang hiển thị Thoả thuận người dùng, quy trình phát hiện và thiết lập thiết bị, cũng như quy trình đặt tên cho thiết bị. Sau khi hoàn tất, quy trình sẽ chuyển tiêu điểm trở lại ứng dụng và truyền kết quả uỷ quyền trong hàm gọi lại mà chúng ta đã phác thảo trong phần trước.
Một lợi ích của Commissioning API là quy trình trải nghiệm người dùng do SDK xử lý, vì vậy, nhà phát triển có thể bắt đầu và chạy rất nhanh. Điều này cũng mang lại cho người dùng trải nghiệm nhất quán khi thêm thiết bị trên nhiều ứng dụng.
Để biết thêm về API thiết lập, hãy truy cập vào trang API thiết lập trên Android.
8. Xin chúc mừng!
Xin chúc mừng! Bạn đã tạo thành công một ứng dụng Android bằng cách sử dụng Google Home API. Trong suốt lớp học lập trình này, bạn đã khám phá các API Quyền, Thiết bị, Cấu trúc và Thiết lập. Trong lớp học lập trình tiếp theo, Tạo quy trình tự động hoá nâng cao bằng Home API trên Lớp học lập trình Android, chúng ta sẽ khám phá Automation API và Discovery API, đồng thời hoàn tất ứng dụng.
Chúng tôi hy vọng bạn sẽ thích thú khi xây dựng các ứng dụng có khả năng điều khiển thiết bị một cách sáng tạo trong hệ sinh thái Google Home.
Các bước tiếp theo
- Tiếp tục tìm hiểu về Home API trên Android bằng cách hoàn thành lớp học lập trình thứ hai trong loạt lớp học lập trình này: Tạo quy trình tự động hoá nâng cao bằng Home API trên Android.
- Bạn có thể liên hệ với chúng tôi để đưa ra đề xuất hoặc báo cáo mọi vấn đề thông qua Công cụ theo dõi lỗi, chủ đề hỗ trợ Nhà thông minh.