دليل لغات وصف البيانات (DSL) لنظام التشغيل iOS للإجراءات المبرمَجة المعقدة

يمكن استخدام لغة DSL الخاصة ببرامج التشغيل الآلي لإنشاء عمليات تشغيل آلي أكثر تعقيدًا من تلك التي تمت مناقشتها في دليل DSL - عمليات التشغيل الآلي الأساسية على أجهزة iOS.

متسلسلة مع إجراءات متعددة

متسلسلة مع إجراءات متعددة

يمكن أن ينفّذ التشغيل الآلي أكثر من إجراء واحد. على سبيل المثال، بدلاً من عقدة action واحدة، يمكنك استخدام عدة عقد action يتم تشغيلها بشكل تسلسلي:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  starter(...)
  condition {...}
  action {...}
  action {...}
  action {...}

}

متسلسلة مع إجراءات متوازية متعددة

متسلسلة مع إجراءات متوازية متعددة

إذا وضعت عدة عُقد action في عقدة parallel، يتم تنفيذ الإجراءات في الوقت نفسه.

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  starter(...)
  condition {...}
  parallel {
    action {...}
    action {...}
    action {...}
  }

}

إذا كانت هناك عُقد action في العقدة sequential تأتي بعد العقدة parallel، فإنّها تنتظر حتى تنتهي جميع العُقد داخل العقدة parallel من التنفيذ.

التنفيذ الشرطي

تنفّذ عملية التشغيل الآلي العُقد بشكل تسلسلي أو متوازٍ تلقائيًا. إذا كنت بحاجة إلى منطق التفريع الشرطي، أي تنفيذ إجراءات أو مسارات مختلفة استنادًا إلى شروط وقت التشغيل، استخدِم عبارات if-then-else التي يتم إنشاؤها باستخدام كتل DSL للتحكّم في التدفق الشرطي: ifThen وelseIf وorElse.

في حين أنّ عقدة condition العادية تتحكّم في عملية التشغيل الآلي بأكملها (إذا كانت نتيجة تقييم الشرط هي false، يتوقف تنفيذ التشغيل الآلي على الفور)، تتيح وحدات ifThen التحكّم في مسار التشغيل الآلي المتفرّع:

  • عقدة condition: لإيقاف تنفيذ عملية التشغيل الآلي بالكامل (أو مسار التنفيذ الحالي) إذا كان التعبير false.
  • ‫ifThen / elseIf / orElse: لتقييم الشروط بالترتيب إذا كان الشرط false، يتم الانتقال إلى فرع elseIf التالي أو فرع orElse الاحتياطي أو إلى العُقَد اللاحقة في عملية التشغيل الآلي إذا لم يتم استيفاء أي شرط.

تنفيذ إجراء استنادًا إلى شرط معيّن

يقيّم المكوّن ifThen تعبيرًا شرطيًا. إذا تم تقييم التعبير على أنّه true، يتم تنفيذ إجراءات DSL أو العُقد المضمّنة داخل الكتلة. إذا كانت النتيجة false، يتم تخطّي الإجراءات، وتنتقل عملية التشغيل الآلي إلى العُقد اللاحقة في المسار التسلسلي.

يمكنك استخدام مجموعة ifThen مستقلة عندما تريد فقط تنفيذ إجراء بشكل مشروط بدون حظر أو إنهاء العُقَد اللاحقة في التشغيل الآلي:

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
typealias ContactSensorDevice = Matter.ContactSensorDeviceType
typealias BooleanStateTrait = Matter.BooleanStateTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let contactState = starter(
    contactSensor,
    ContactSensorDevice.self,
    BooleanStateTrait.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  contactState
  lightState

  condition {
    // Door opened (contact sensor open)
    contactState.stateValue.equals(false)
  }

  // Conditionally turn on the light if it's off
  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }

  // Continue executing subsequent actions in the sequential flow
  action(structure) {
    Google.AssistantBroadcastTrait.broadcast(msg: "The door was opened.")
  }
}

تنفيذ إجراءات مختلفة استنادًا إلى شرط معيّن

لتنفيذ مجموعة واحدة من الإجراءات عندما يكون الشرط صحيحًا ومجموعة بديلة من الإجراءات عندما يكون الشرط خاطئًا، يمكنك ربط كتلة .orElse { ... } الاختيارية بعد ifThen(...) { ... }:

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLockTrait = Matter.DoorLockTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let doorLockEvent = starter(
    doorLock,
    DoorLockDevice.self,
    DoorLockTrait.LockOperationEvent.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  doorLockEvent
  lightState

  condition {
    doorLockEvent.lockOperationType.equals(.unlock)
  }

  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }.orElse {
    action(structure) {
      Google.AssistantBroadcastTrait.broadcast(msg: "Welcome home!")
    }
  }
}

ربط شروط متعددة في تسلسل

يمكنك ربط كتلة .elseIf(...) { ... } اختيارية واحدة أو أكثر لتقييم شروط متعددة بالتسلسل. يتم تنفيذ الفرع الأول الذي يتم تقييم شرطه على أنّه true، ويتم تخطّي جميع الفروع المتبقية. إذا لم يتم تقييم أي من الشروط على أنّها true، يتم تنفيذ مجموعة .orElse { ... } اختيارية (إذا تم توفيرها):

// Adjust climate controls based on room temperature changes.
typealias TemperatureSensorDeviceType = Matter.TemperatureSensorDeviceType
typealias TemperatureMeasurementTrait = Matter.TemperatureMeasurementTrait
typealias ThermostatDeviceType = Matter.ThermostatDeviceType
typealias SimplifiedThermostatTrait = Google.SimplifiedThermostatTrait
typealias FanDeviceType = Matter.FanDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let tempStarter = starter(
    tempSensor,
    TemperatureSensorDeviceType.self,
    TemperatureMeasurementTrait.self
  )
  tempStarter

  // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
  ifThen(tempStarter.measuredValue.greaterThanOrEquals(2800)) {
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .cool)
    }
  }.elseIf(tempStarter.measuredValue.lessThan(1800)) {
    // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .heat)
    }
  }.orElse {
    // Otherwise, turn on the fan
    action(fan, FanDeviceType.self) {
      OnOffTrait.on()
    }
  }
}

المسارات المشروطة المُدمَجة

يمكن دمج الوحدات الشرطية داخل وحدات ifThen أو elseIf أو orElse أخرى، بالإضافة إلى دمجها مع عُقد parallel وdelay(for:) وstateReader.

تنفّذ الكتل ifThen وelseIf وorElse محتواها على شكل تسلسلات متتابعة. يمكنك وضع أي عُقد متسلسلة داخل كل فرع، بما في ذلك action وstateReader وparallel وdelay(for:) ومجموعات ifThen المتداخلة.

التأخيرات

يمكنك إدخال فترات توقّف مؤقت في عمليات التشغيل الآلي باستخدام الطريقة delay(for:)، التي تأخذ وسيطة Duration تمثّل مدة التوقّف المؤقت قبل مواصلة التنفيذ. قد تكون مدة الإيقاف المؤقت قصيرة تصل إلى خمس ثوانٍ أو طويلة تصل إلى 24 ساعة.

على سبيل المثال، لتبديل حالة مصباح أربع مرات مع توقّف مؤقت لمدة خمس ثوانٍ بين كل تبديل:

typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

sequential {
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

تفعيل ميزة "إيقاف"

ميزة "إيقاف التفعيل" هي ميزة تتيح لعملية التشغيل الآلي تجاهل starter لفترة زمنية محدّدة بعد حدث التفعيل الأوّلي. على سبيل المثال، إذا كانت عملية التشغيل الآلي تتضمّن starter يتم تفعيله من خلال كشف الحركة، وإذا حدّدت مدة منع تفعيل تبلغ خمس دقائق، لن يتم تفعيل starter مرة أخرى خلال الدقائق الخمس التالية. يمنع هذا الإجراء تفعيل التشغيل الآلي بشكل سريع ومتكرر.

لتطبيق ميزة "إيقاف المشغّلات" على عملية التشغيل الآلي، استخدِم الكلمة الرئيسية suppress(for:) مع الوسيطة Duration التي تمثّل مدة الانتظار قبل الاستجابة للمشغّلات اللاحقة. قد تكون مدة الإيقاف قصيرة لمدة خمس ثوانٍ أو طويلة لمدة 24 ساعة.

typealias OccupancySensorDevice = Matter.OccupancySensorDeviceType
typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias MotionDetectionTrait = Google.MotionDetectionTrait
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let starterNode = starter(device, OccupancySensorDevice.self, MotionDetectionTrait.self)
  starterNode
  suppress(for: .seconds(30 * 60)) // 30 minutes
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

يُرجى العِلم أنّ إيقاف المشغّلات يؤثر في جميع starters في عملية التشغيل الآلي التي تسبق Suppression.

الحدّ من عدد عمليات التنفيذ

يمكنك تحديد عدد المرات المسموح فيها بتشغيل عملية التشغيل الآلي.

على سبيل المثال، قد تحتاج إلى إعداد عملية تشغيل آلي لمرة واحدة لتشغيل المكنسة الكهربائية أثناء غيابك عن المنزل طوال اليوم.

لإجراء ذلك، اضبط حقل البيانات الوصفية maxExecutionCount الخاص بعملية التشغيل الآلي. المثال التالي هو عملية تشغيل آلي يمكن تنفيذها مرة واحدة فقط:

import GoogleHomeSDK
import GoogleHomeTypes

typealias RoboticVacuumCleanerDevice = Matter.RoboticVacuumCleanerDeviceType
typealias RvcRunModeTrait = Matter.RvcRunModeTrait
typealias AreaPresenceStateTrait = Google.AreaPresenceStateTrait

let draftAutomation = automation(
  name: "Vacuum home away",
  description: "Run the vacuum once when everyone is away.",
  maxExecutionCount: 1
) {
  let homeAwayState = starter(structure, AreaPresenceStateTrait.self)
  homeAwayState

  condition {
    homeAwayState.presenceState.equals(.presenceStateVacant)
  }

  action(vacuum, RoboticVacuumCleanerDevice.self) {
    RvcRunModeTrait.changeToMode(newMode: 1)
  }
}

يتم حذف عملية التشغيل الآلي فورًا بعد اكتمال تنفيذها للمرة الأخيرة والوصول إلى maxExecutionCount. يبقى إدخال سجلّ التشغيل الآلي في علامة التبويب Google Home app (GHA) النشاط، بما في ذلك automation_id.

ضبط سمات السمات في إجراء

لضبط قيمة سمة معيّنة:

  1. أنشئ عقدة update ضمن عقدة action، مع تضمين السمة ذات الصلة كوسيطة لعقدة update:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
    
  2. ضمن العقدة update، لكل سمة يتم تعديلها، استخدِم دالة متغيّرة، ومرِّر القيمة الجديدة إليها. لتشكيل اسم دالة التغيير:
    1. استخدِم أحرفًا كبيرة في اسم السمة
    2. أضِف كلمة set كبادئة.
    على سبيل المثال، لتعديل سمة باسم defaultMoveRate، عليك استخدام دالة متغيّرة باسم setDefaultMoveRate.

يُرجى العِلم أنّ عقدة update يمكن أن تتضمّن دوال متعدّدة لتغيير البيانات. في ما يلي مثال على تعديل سمتَين:

typealias FanDeviceType = Matter.FanDeviceType
typealias FanControlTrait = Matter.FanControlTrait

action(fan, FanDeviceType.self) {
  update(FanControlTrait.self) {
    $0.setFanMode(.on)
  }
}