التحكّم في الأجهزة

التحقّق مما إذا كانت السمة تتيح استخدام أمر

يمكن أيضًا التحقّق من توفّر دعم لأمر السمة. استخدِم أيضًا دالة supports على مستوى السمة للتحقّق مما إذا كان الأمر متوافقًا مع جهاز معيّن.

على سبيل المثال، للتحقّق من توافق الجهاز مع الأمر toggle الخاص بالسمة "تشغيل/إيقاف":

// Check if the OnOff trait supports the toggle command.
if (onOffTrait.supports(OnOff.Command.Toggle)) {
  println("onOffTrait supports toggle command")
} else {
  println("onOffTrait does not support stateful toggle command")
}

إرسال أمر إلى جهاز

يشبه إرسال أمر قراءة سمة حالة من سمة. لتفعيل الجهاز أو إيقافه، استخدِم الأمر Toggle لسمة OnOff ، والذي تم تحديده في toggle() في toggle(). تعمل هذه الطريقة على تغيير onOff إلى false إذا كانت true، أو إلى true إذا كانت false:

// Calling a command on a trait.
try {
  onOffTrait.toggle()
} catch (e: HomeException) {
  // Code for handling the exception
}

جميع أوامر السمات هي وظائف suspend ولا تكتمل إلا عندما تُرسل واجهة برمجة التطبيقات (API) رداً (مثل تأكيد تغيُّر حالة الجهاز). قد تُعرِض الأوامر استثناءً إذا تم رصد مشكلة في تدفق التنفيذ. بصفتك مطوِّرًا، عليك استخدام رمز try-catch لمعالجة هذه الاستثناءات بشكلٍ سليم، وعرض معلومات تفصيلية للمستخدمين في الحالات التي يمكن فيها اتخاذ إجراء بشأن الأخطاء. سيؤدي عدم معالجة الاستثناءات إلى إيقاف وقت تشغيل التطبيق، وقد يؤدي ذلك بدوره إلى تعطُّل التطبيق.

بدلاً من ذلك، يمكنك استخدام الأمرَين off() أو on() لضبط الحالة صراحةً:

onOffTrait.off()
onOffTrait.on()

بعد إرسال أمر لتغيير الحالة، يمكنك قراءة الحالة كما هو موضّح في قراءة حالة الجهاز بعد اكتمال العملية من أجل معالجتها في تطبيقك. بدلاً من ذلك، يمكنك استخدام عمليات المعالجة كما هو موضّح في مراقبة الحالة، وهي الطريقة المفضّلة.

إرسال أمر يتضمّن مَعلمات

قد تستخدم بعض الطلبات مَعلمات، مثل تلك الواردة في سمات OnOff أو LevelControl:

offWithEffect

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)

moveToLevel

// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

تحتوي بعض الأوامر على وسيطات اختيارية تأتي بعد الوسائط المطلوبة.

على سبيل المثال، يحتوي الأمر step الخاص بالسمة FanControl على وسيطتَين اختياريتين:

val fanControlTraitFlow: Flow<FanControl?> =
  device.type(FanDevice).map { it.standardTraits.fanControl }.distinctUntilChanged()

val fanControl = fanControlTraitFlow.firstOrNull()

// Calling a command with optional parameters not set.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase)

// Calling a command with optional parameters.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) { wrap = true }

التحقّق مما إذا كانت السمة تتيح استخدام سمة أخرى

قد تتوافق بعض الأجهزة مع سمة Matter، ولكن ليس سمة معيّنة. على سبيل المثال، قد لا يتيح جهاز Cloud-to-cloud الذي تم ربطه بـ Matter كل سمة Matter. لحلّ هذه الحالات، استخدِم دالة supports على مستوى السمة وقائمة القيم الفريدة Attribute للسمة للتحقّق مما إذا كانت السمة متوافقة مع جهاز معيّن.

على سبيل المثال، للتحقّق من توافق الجهاز مع سمة "تشغيل/إيقاف" onOff:

// Check if the OnOff trait supports the onOff attribute.
if (onOffTrait.supports(OnOff.Attribute.onOff)) {
  println("onOffTrait supports onOff state")
} else {
  println("onOffTrait is for a command only device!")
}

تكون بعض السمات فارغة في مواصفات Matter أو مخطّط Cloud-to-cloud smart home. بالنسبة إلى هذه السمات، يمكنك تحديد ما إذا كانت القيمة null التي تعرضها السمة ناتجة عن عدم إدراج الجهاز لهذه القيمة، أو ما إذا كانت قيمة السمة هي null فعلاً، وذلك باستخدام isNullable بالإضافة إلى supports:

// Check if a nullable attribute is set or is not supported.
if (onOffTrait.supports(OnOff.Attribute.startUpOnOff)) {
  // The device supports startupOnOff, it is safe to expect this value in the trait.
  if (OnOff.Attribute.startUpOnOff.isNullable && onOffTrait.startUpOnOff == null) {
    // This value is nullable and set to null. Check the specification as to
    // what null in this case means
    println("onOffTrait supports startUpOnOff and it is null")
  } else {
    // This value is nullable and set to a value.
    println("onOffTrait supports startUpOnOff and it is set to ${onOffTrait.startUpOnOff}")
  }
} else {
  println("onOffTrait does not support startUpOnOff!")
}

تعديل سمات السمات

إذا كنت تريد تغيير قيمة سمة معيّنة، ولم تنفِّذ أيّ من تعليمات السمة ذلك، قد تتيح السمة ضبط قيمتها بشكل صريح.

يعتمد ما إذا كان يمكن تغيير قيمة سمة على عاملَين:

  • هل السمة قابلة للكتابة؟
  • هل يمكن أن تتغيّر قيمة السمة كأثر جانبي لإرسال أحد ملفّات برمجية السمات؟

توفّر المستندات المرجعية للصفات وسماتها هذه الاطّلاع على هذه الاطّلاع على هذه المعلومات.

وبالتالي، فإنّ مجموعات السمات التي تحدّد كيفية تغيير قيمة السمة هي:

  • للقراءة فقط ولا تتأثر بالأوامر الأخرى. وهذا يعني أنّ قيمة السمة لا تتغيّر. على سبيل المثال، سمة currentPosition لسمة Switch.

  • للقراءة فقط وتتأثر بأوامر أخرى. وهذا يعني أنّ الطريقة الوحيدة التي يمكن بها تغيير قيمة السمة هي نتيجة إرسال أمر. على سبيل المثال، السمة currentLevel لسمة LevelControl Matter هي للقراءة فقط، ولكن يمكن تغيير قيمتها باستخدام أوامر مثل moveToLevel.

  • يمكن الكتابة فيها ولا تتأثر بأوامر أخرى. وهذا يعني أنّه يمكنك تغيير قيمة السمة مباشرةً باستخدام الدالة update للسمة، ولكن لا تتوفّر أي أوامر ستؤثّر في قيمة السمة. على سبيل المثال، سمة WrongCodeEntryLimit لسمة DoorLock.

  • يمكن الكتابة فيها وتتأثر بأوامر أخرى. وهذا يعني أنّه يمكنك تغيير قيمة السمة مباشرةً باستخدام الدالة update للسمة، ويمكن أن تتغيّر قيمة السمة نتيجةً لإرسال أمر. على سبيل المثال، يمكن كتابة قيمة في سمة occupiedCoolingSetpoint لسمة Thermostat وتعديلها أيضًا باستخدام العبارة setpointRaiseLower.

مثال على استخدام الدالة update لتغيير قيمة سمة

يوضّح هذا المثال كيفية ضبط قيمة سمة DoorLockTrait.WrongCodeEntryLimit بشكل صريح.

لضبط قيمة سمة، استخدِم دالة update للسمة واضبط لها دالة مُعدِّلة تضبط القيمة الجديدة. من الممارسات الجيدة أولاً التحقّق من أنّ السمة تتيح استخدام سمة.

على سبيل المثال:

    var doorLockDevice = home.devices().list().first { device -> device.has(DoorLock) }

    val traitFlow: Flow<DoorLock?> =
      doorLockDevice.type(DoorLockDevice).map { it.standardTraits.doorLock }.distinctUntilChanged()

    val doorLockTrait: DoorLock = traitFlow.first()!!

    if (doorLockTrait.supports(DoorLock.Attribute.wrongCodeEntryLimit)) {
      val unused = doorLockTrait.update { setWrongCodeEntryLimit(3u) }
    }