يمكن الوصول إلى واجهات برمجة التطبيقات Structure API من خلال واجهات برمجة تطبيقات Home لنظام التشغيل Android. استورِد هذه الحِزم إلى تطبيقك:
import com.google.home.Home
import com.google.home.Id
import com.google.home.Structure
معالجة الأخطاء
يمكن لأي طريقة في Home APIs أن تؤدي إلى ظهور
HomeException، لذا ننصحك باستخدام مجموعة try-catch
لرصد HomeException في جميع الطلبات.
عند التعامل مع HomeException، تحقَّق من حقلَي
error.code و
error.message لمعرفة الخطأ الذي حدث. قد تكون هناك رموز أخطاء فرعية
أيضًا، لذا يمكنك استدعاء طريقة
getSubErrorCodes() والتحقّق من النتيجة.
ستؤدي أي استثناءات لم تتم معالجتها إلى تعطُّل تطبيقك.
لمزيد من المعلومات، يُرجى الاطّلاع على معالجة الأخطاء.
عيّنة من المكالمات
الحصول على قائمة بالبُنى
بعد الإعداد، يعرض طلب structures() تدفقًا من البُنى
المتاحة لك:
// 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() هي مسار قد لا يعرض على الفور قائمة صالحة بالبُنى. إذا كان تطبيقك تفاعليًا ويشترك في هذا التدفق لتشغيل واجهة المستخدم، فيجب في النهاية عرض قائمة صالحة من الهياكل.
هناك حالات أخرى يمكن فيها عرض قائمة فارغة، على سبيل المثال إذا فقد هاتف المستخدم إمكانية الاتصال أو إذا أبطل المستخدم الأذونات الممنوحة لتطبيقك. يجب التأكّد من معالجة هذه الحالات في تطبيقك.
بدلاً من ذلك، إذا كانت البرمجة الإلزامية مطلوبة بشدة بدلاً من البرمجة التفاعلية، يمكن استخدام عامل تشغيل التدفق الطرفي:
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!!)
يمكنك أيضًا حذف غرفة باستخدام معرّف فقط:
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!!))
إذا كان لديك معرّفات الأجهزة والغرف فقط، يمكنك أيضًا نقل الأجهزة:
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. للاستعلام عن مجموعات الأجهزة والتفاعل معها، أدرِج DeviceGroup في قائمة entityTypes عند إعداد FactoryRegistry، بالإضافة إلى السمات Group وGroupManagement وGroupMembership.
يمكنك التفاعل مع الأجهزة في مجموعة إما من خلال تكرار أجهزتها الأعضاء مباشرةً (راجِع التفاعل مع الأجهزة الأعضاء في المجموعة) أو من خلال استهداف جزء من نوع الجهاز على DeviceGroup (راجِع التحكّم في مجموعة أجهزة).
الحصول على قائمة بمجموعات الأجهزة
لمراقبة جميع مجموعات الأجهزة في بنية معيّنة، يمكنك استدعاء home.entities(DeviceGroup)
والفلترة حسب معرّف البنية:
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()
}
يمكنك أيضًا تعديل سمة في جميع الأجهزة الأعضاء المطابقة في مجموعة
(على سبيل المثال، ضبط onTransitionTime على 1u في جميع الأعضاء
DimmableLightDevice) وانتظار اكتمال العملية خلال مهلة محدّدة:
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، يُرجى الاطّلاع على نظرة عامة على واجهة برمجة تطبيقات التشغيل الآلي على Android.