Structure API در Android

Structure API ممکن است ازطریق Home API برای 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() یک 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 جریانی است که ممکن است فوراً فهرست معتبری از ساختارها را برنگرداند. اگر برنامه‌تان واکنشی است و برای هدایت واسط کاربر در آن جریان مشترک می‌شود، درنهایت باید فهرست معتبری از ساختارها برگردانده شود. موقعیت‌های دیگری نیز وجود دارد که ممکن است فهرست ساختار خالی برگردانده شود، برای مثال اگر اتصال تلفن کاربر قطع شود یا اگر کاربر اجازه‌های اعطاشده به برنامه شما را لغو کرده باشد. باید مطمئن شوید که این موارد را در برنامه‌تان مدیریت می‌کنید.

یا اگر به‌جای برنامه‌نویسی واکنشی، برنامه‌نویسی امری به‌شدت موردنیاز است، می‌توان از اپراتور جریان پایانه استفاده کرد:

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")

اگر نام‌ها از حد ۶۰ نقطه کد یونی‌کد (نویسه) فراتر برود، کوتاه می‌شود و هیچ خطایی نشان داده نخواهد شد. توسعه‌دهندگان مسئول مدیریت نام‌های طولانی هستند و برای مثال می‌توانند تصمیم بگیرند که آیا می‌خواهند به کاربران اطلاع دهند که نام‌ها کوتاه خواهد شد یا نه.

در بوم‌سازگان 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 حفظ می‌شود و برای دیگر اعضای ساختار و دیگر برنامه‌هایی که به ساختار دسترسی دارند قابل‌مشاهده است.

مانند اتاق‌های فیزیکی، گروه‌های دستگاه به یک ساختار تعلق دارند. اما برخلاف اتاق‌ها، گروه‌های دستگاه گروه‌بندی‌های منطقی هستند. یک دستگاه می‌تواند به‌طور هم‌زمان به چند گروه دستگاه تعلق داشته باشد. گروه‌های دستگاه می‌توانند تا ۱۰۰ دستگاه داشته باشند.

گروه‌های دستگاه با موجودیت DeviceGroup نشان داده می‌شوند که با HomeDevice متفاوت است. برای جستجو و تعامل با گروه‌های دستگاه، هنگام مقداردهی اولیه FactoryRegistry، DeviceGroup را در فهرست entityTypes به‌همراه ویژگی‌های 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 APIs، به نمای کلی Automation API در Android مراجعه کنید.