يمكن الوصول إلى Automation APIs من خلال Home APIs لنظام Android، ولكن بما أنّ نقطة الدخول إليها تكون من خلال بنية، يجب أولاً منح الإذن بالوصول إلى البنية قبل أن يصبح بالإمكان استخدامها.
بعد منح الأذونات لبنية معيّنة، استورِد هذه الحِزم إلى تطبيقك:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
تحتوي البنية على
HasAutomations
واجهة تتضمّن الطرق التالية الخاصة بالتشغيل الآلي:
| واجهة برمجة التطبيقات | الوصف |
|---|---|
automations() |
تعرِض هذه الطريقة جميع عمليات التشغيل الآلي التي تنتمي إلى البنية. ولا يتم عرض سوى عمليات التشغيل الآلي التي أنشأتها من خلال Home APIs. |
createAutomation(automation) |
تنشئ هذه الطريقة نموذجًا لعملية تشغيل آلي لبنية معيّنة. |
deleteAutomation(automationId) |
تحذف هذه الطريقة نموذجًا لعملية تشغيل آلي حسب رقم التعريف. |
إنشاء عملية تشغيل آلي
بعد إنشاء نموذج من Home والحصول على الأذونات من المستخدِم، احصل على البنية والأجهزة:
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
بعد ذلك، حدِّد منطق عملية التشغيل الآلي باستخدام Automation DSL. في Home APIs، يتم تمثيل عملية التشغيل الآلي من خلال واجهة Automation. تحتوي هذه الواجهة على مجموعة من الخصائص:
- البيانات الوصفية، مثل الاسم والوصف
- العلامات التي تشير، مثلاً، إلى ما إذا كان يمكن تنفيذ عملية التشغيل الآلي أم لا
- قائمة بالعُقد التي تحتوي على منطق عملية التشغيل الآلي، والتي تُعرف باسم الرسم البياني للتشغيل الآلي، ويتم تمثيلها من خلال السمة
automationGraph
يكون نوع automationGraph تلقائيًا هو SequentialFlow، وهو فئة تحتوي على قائمة بالعُقد التي يتم تنفيذها بترتيب تسلسلي. تمثّل كل عُقدة عنصرًا من عناصر عملية التشغيل الآلي، مثل إجراء التفعيل أو الشرط أو الإجراء.
عيِّن name وdescription لعملية التشغيل الآلي.
عند إنشاء عملية تشغيل آلي، يتم ضبط العلامة isActive تلقائيًا على true، لذا ليس من الضروري ضبط هذه العلامة بشكل صريح ما لم تكن تريد إيقاف عملية التشغيل الآلي في البداية. في هذا السيناريو، اضبط العلامة على false أثناء الإنشاء.
تُستخدَم واجهة DraftAutomation لإنشاء عمليات التشغيل الآلي،
بينما تُستخدَم واجهة Automation لاستردادها. على سبيل المثال، إليك Automation DSL لعملية تشغيل آلي تُشغِّل جهازًا عند تشغيل جهاز آخر:
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.Condition
import com.google.home.automation.DraftAutomation
import com.google.home.automation.Equals
import com.google.home.automation.Node
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.matter.standard.OnOff
import com.google.home.Structure
...
val automation: DraftAutomation = automation {
name = "MyFirstAutomation"
description = "Turn on a device when another device is turned on."
sequential {
val starterNode = starter<_>(device1, OnOffLightDevice, trait=OnOff)
condition() { expression = stateReaderNode.onOff equals true }
action(device2, OnOffLightDevice) { command(OnOff.on()) }
}
}
بعد تحديد Automation DSL، مرِّرها إلى الـ
createAutomation()
لإنشاء نموذج DraftAutomation
val createdAutomation = structure.createAutomation(automation)
من هنا، يمكنك استخدام جميع طرق التشغيل الآلي الأخرى في عملية التشغيل الآلي، مثل execute() وstop() وupdate().
أخطاء التحقق من الصحة
إذا لم تجتاز عملية إنشاء التشغيل الآلي عملية التحقق من الصحة، ستوفّر رسالة تحذير أو خطأ معلومات حول المشكلة. لمزيد من المعلومات، يُرجى الرجوع إلى المرجع
ValidationIssueType.
أمثلة للرموز البرمجية
نعرض هنا بعض الأمثلة على الرموز البرمجية التي يمكن استخدامها لتنفيذ أجزاء من عمليات التشغيل الآلي الافتراضية الموضّحة في صفحة تصميم عملية تشغيل آلي على Android.
عملية تشغيل آلي بسيطة
يمكن تنفيذ عملية تشغيل آلي ترفع الستائر في الساعة 8:00 صباحًا على النحو التالي:
// get all the automation node candidates in the structure
val allCandidates = structure.allCandidates().first()
// determine whether a scheduled automation can be constructed
val isSchedulingSupported =
allCandidates.any {
it is EventCandidate &&
it.eventFactory == Time.ScheduledTimeEvent &&
it.unsupportedReasons.isEmpty()
}
// get the blinds present in the structure
val blinds =
allCandidates
.filter {
it is CommandCandidate &&
it.commandDescriptor == WindowCoveringTrait.UpOrOpenCommand &&
it.unsupportedReasons.isEmpty()
}
.map { it.entity }
.filterIsInstance<HomeDevice>()
.filter { it.has(WindowCoveringDevice) }
if (isSchedulingSupported && blinds.isNotEmpty()) {
// Proceed to create automation
val automation: DraftAutomation = automation {
name = "Day time open blinds"
description = "Open all blinds at 8AM everyday"
isActive = true
sequential {
// At 8:00am local time....
val unused =
starter(structure, Time.ScheduledTimeEvent) {
parameter(Time.ScheduledTimeEvent.clockTime(LocalTime.of(8, 0, 0, 0)))
}
// ...open all the blinds
parallel {
for (blind in blinds) {
action(blind, WindowCoveringDevice) { command(WindowCovering.upOrOpen()) }
}
}
}
}
val createdAutomation = structure.createAutomation(automation)
} else if (!isSchedulingSupported) {
// Cannot create automation.
// Set up your address on the structure, then try again.
} else {
// You don't have any WindowCoveringDevices.
// Try again after adding some blinds to your structure.
}
عملية تشغيل آلي معقّدة
يمكن تنفيذ عملية تشغيل آلي تُشغِّل الأضواء الوامضة عند رصد الحركة على النحو التالي:
import com.google.home.Home
import com.google.home.HomeClient
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
import com.google.home.automation.action
import com.google.home.automation.automation
import com.google.home.automation.equals
import com.google.home.automation.parallel
import com.google.home.automation.starter
import com.google.home.google.AssistantBroadcast
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOff.Companion.toggle
import com.google.home.matter.standard.OnOffLightDevice
import java.time.Duration
// get all the automation node candidates in the structure
val allCandidates = structure.allCandidates().first()
// get the lights present in the structure
val availableLights = allCandidates.filter {
it is CommandCandidate &&
it.commandDescriptor == OnOffTrait.OnCommand
}.map { it.entity }
.filterIsInstance<HomeDevice>()
.filter {it.has(OnOffLightDevice) ||
it.has(ColorTemperatureLightDevice) ||
it.has(DimmableLightDevice) ||
it.has(ExtendedColorLightDevice)}
val selectedLights = ... // user selects one or more lights from availableLights
automation {
isActive = true
sequential {
// If the presence state changes...
val starterNode = starter<_>(structure, AreaPresenceState)
// ...and if the area is occupied...
condition() {
expression = starterNode.presenceState equals PresenceState.PresenceStateOccupied
}
// "blink" the light(s)
parallel {
for(light in selectedLights) {
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle())}
}
}
}
}
اختيار الأجهزة ديناميكيًا باستخدام فلاتر الكيانات
عند كتابة عملية تشغيل آلي، لا يقتصر الأمر على تحديد أجهزة معيّنة. تتيح ميزة فلاتر الكيانات لعملية التشغيل الآلي اختيار الأجهزة في وقت التشغيل استنادًا إلى معايير مختلفة.
على سبيل المثال، باستخدام فلاتر الكيانات، يمكن أن تستهدف عملية التشغيل الآلي ما يلي:
- جميع الأجهزة من نوع جهاز معيّن
- جميع الأجهزة في غرفة معيّنة
- جميع الأجهزة من نوع جهاز معيّن في غرفة معيّنة
- جميع الأجهزة التي تم تشغيلها
- جميع الأجهزة التي تم تشغيلها في غرفة معيّنة
لاستخدام فلاتر الكيانات:
- في
StructureأوRoom، استخدِم الطريقةatExecutionTime(). تعرِض هذه الطريقةTypedExpression<TypedEntity<StructureType>>. - في هذا العنصر، استخدِم الطريقة
getDevicesOfType()، مع تمريرDeviceTypeإليها.
يمكن استخدام فلاتر الكيانات في إجراءات التفعيل وقارئات الحالة والإجراءات.
على سبيل المثال، لجعل أي ضوء تشغيل/إيقاف يُفعِّل عملية تشغيل آلي من إجراء تفعيل:
// If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
لالتقاط حالة OnOff لجميع الأضواء في بنية معيّنة (على وجه التحديد، أضواء التشغيل/الإيقاف) في قارئ الحالة:
// Build a Map<Entity, OnOff> val onOffStateOfAllLights = stateReader( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
للحصول على الأضواء في غرفة معيّنة واستخدامها في شرط:
val livingRoomLights = stateReader( entityExpression = livingRoom.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, ) // Are any of the lights in the living room on? condition { expression = livingRoomLights.values.any { it.onOff equals true } }
في وقت التشغيل:
| السيناريو | النتيجة |
|---|---|
| ما مِن أجهزة تستوفي المعايير في إجراء التفعيل. | لا يتم تفعيل عملية التشغيل الآلي. |
| ما مِن أجهزة تستوفي المعايير في قارئ الحالة. | تبدأ عملية التشغيل الآلي ولكنها ستستمر استنادًا إلى عُقدة الشرط. |
| ما مِن أجهزة تستوفي المعايير في إجراء معيّن. | تبدأ عملية التشغيل الآلي ولكن لا يُنفِّذ الإجراء أي شيء. |
المثال التالي هو عملية تشغيل آلي تُطفئ جميع الأضواء باستثناء ضوء القاعة كلما تم إطفاء ضوء فردي:
val unused = automation { sequential { // If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, ) condition { // Check to see if the triggering light was turned off expression = starter.onOff equals false } // Turn off all lights except the hall light action( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice).filter { it notEquals entity(hallwayLight, OnOffLightDevice) } ) { command(OnOff.on()) } } }
تنفيذ عملية تشغيل آلي
يمكنك تنفيذ عملية تشغيل آلي تم إنشاؤها باستخدام الـ
execute()
طريقة:
createdAutomation.execute()
إذا كانت عملية التشغيل الآلي تتضمّن إجراء تفعيل يدويًا، تبدأ الطريقة `execute()` عملية التشغيل الآلي من تلك النقطة، مع تجاهل جميع العُقد التي تسبق إجراء التفعيل اليدوي.execute() إذا لم تتضمّن عملية التشغيل الآلي إجراء تفعيل يدويًا، يبدأ التنفيذ من العُقدة التي تلي أول عُقدة إجراء تفعيل.
إذا تعذّر تنفيذ العملية execute()، قد يتم عرض HomeException. الاطّلاع على معالجة
الأخطاء.
إيقاف عملية تشغيل آلي
يمكنك إيقاف عملية تشغيل آلي قيد التنفيذ باستخدام الطريقة stop():
createdAutomation.stop()
إذا تعذّر تنفيذ العملية stop()، قد يتم عرض HomeException. الاطّلاع على معالجة
الأخطاء.
الحصول على قائمة بعمليات التشغيل الآلي لبنية معيّنة
يتم تحديد عمليات التشغيل الآلي على مستوى البنية. يمكنك استخدام Collect في
automations()
الخاصة بالبنية للوصول إلى Flow لعمليات التشغيل الآلي:
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
structure.automations().collect {
println("Available automations:")
for (automation in it) {
println(String.format("%S %S", "$automation.id", "$automation.name"))
}
}
بدلاً من ذلك، يمكنك تعيينها إلى Collection محلية:
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
var myAutomations: Collection<Automation> = emptyList()
myAutomations = structure.automations()
الحصول على عملية تشغيل آلي حسب رقم التعريف
للحصول على عملية تشغيل آلي حسب رقم تعريف التشغيل الآلي، استخدِم الطريقة
automations()
في البنية، وطابِق رقم التعريف:
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
الردّ:
// Here's how the automation looks like in the get response.
// Here, it's represented as if calling a println(automation.toString())
Automation(
name = "automation-name",
description = "automation-description",
isActive = true,
id = Id("automation@automation-id"),
automationGraph = SequentialFlow(
nodes = [
Starter(
entity="device@test-device",
type="home.matter.0000.types.0101",
trait="OnOff@6789..."),
Action(
entity="device@test-device",
type="home.matter.0000.types.0101",
trait="OnOff@8765...",
command="on")
]))
الحصول على عملية تشغيل آلي حسب الاسم
يمكن استخدام الطريقة
filter()
في Kotlin لزيادة تحسين طلبات البيانات من واجهة برمجة التطبيقات. للحصول على عملية تشغيل آلي حسب الاسم، احصل على عمليات التشغيل الآلي الخاصة بالبنية وفلترها حسب اسم عملية التشغيل الآلي:
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().filter {
it.name.equals("Sunset Blinds") }
الحصول على جميع عمليات التشغيل الآلي لجهاز معيّن
للحصول على جميع عمليات التشغيل الآلي التي تشير إلى جهاز معيّن، استخدِم الفلترة المتداخلة لفحص automationGraph لكل عملية تشغيل آلي:
import android.util.Log
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.Automation.automationGraph
import com.google.home.automation.Node
import com.google.home.automation.ParallelFlow
import com.google.home.automation.SelectFlow
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.automation.StateReader
...
fun collectDescendants(node: Node): List<Node> {
val d: MutableList<Node> = mutableListOf(node)
val children: List<Node> =
when (node) {
is SequentialFlow -> node.nodes
is ParallelFlow -> node.nodes
is SelectFlow -> node.nodes
else -> emptyList()
}
for (c in children) {
d += collectDescendants(c)
}
return d
}
val myDeviceId = "device@452f78ce8-0143-84a-7e32-1d99ab54c83a"
val structure = homeManager.structures().list().single()
val automations =
structure.automations().first().filter {
automation: Automation ->
collectDescendants(automation.automationGraph!!).any { node: Node ->
when (node) {
is Starter -> node.entity.id.id == myDeviceId
is StateReader -> node.entity.id.id == myDeviceId
is Action -> node.entity.id.id == myDeviceId
else -> false
}
}
}
تعديل عملية تشغيل آلي
لتعديل البيانات الوصفية لعملية تشغيل آلي، استخدِم الطريقة
update()
، مع تمرير تعبير لامدا يضبط البيانات الوصفية:
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
automation.update { this.name = "Flashing lights 2" }
تتيح الطريقة update()
استبدال الرسم البياني للتشغيل الآلي بالكامل، ولكن لا تتيح تعديل الرسم البياني لكل عُقدة. ويُعدّ تعديل الرسم البياني لكل عُقدة أمرًا عرضة للخطأ بسبب الترابط بين العُقد. إذا أردت تغيير منطق عملية تشغيل آلي، أنشئ رسمًا بيانيًا جديدًا واستبدِل الرسم البياني الحالي بالكامل.
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: Automation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
automation.update {
this.automationGraph = sequential {
val laundryWasherCompletionEvent =
starter<_>(laundryWasher, LaundryWasherDevice, OperationCompletionEvent)
condition {
expression =
laundryWasherCompletionEvent.completionErrorCode equals
// UByte 0x00u means NoError
0x00u
}
action(speaker, SpeakerDevice) { command(AssistantBroadcast.broadcast("laundry is done")) }
}
}
}
حذف عملية تشغيل آلي
لحذف عملية تشغيل آلي، استخدِم الطريقة
deleteAutomation()
الخاصة بالبنية. يجب حذف عملية التشغيل الآلي باستخدام رقم تعريفها.
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().first()
structure.deleteAutomation(automation.id)
إذا تعذّر الحذف، قد يتم عرض HomeException. الاطّلاع على معالجة
الأخطاء.
تأثير حذف الجهاز على عمليات التشغيل الآلي
إذا حذف مستخدِم جهازًا مستخدَمًا في عملية تشغيل آلي، لن يتمكّن الجهاز المحذوف من تفعيل أي إجراءات تفعيل، ولن تتمكّن عملية التشغيل الآلي من قراءة السمات منه أو إصدار أوامر إليه. على سبيل المثال، إذا حذف مستخدِم
OccupancySensorDevice
من منزله، وكانت عملية التشغيل الآلي تتضمّن إجراء تفعيل يعتمد على
الـ OccupancySensorDevice، لن يتمكّن إجراء التفعيل هذا من تفعيل عملية التشغيل الآلي بعد الآن.