অটোমেশন API, Android-এর জন্য Home API-এর মাধ্যমে অ্যাক্সেস করা যেতে পারে, কিন্তু যেহেতু এগুলির এন্ট্রি পয়েন্ট একটি স্ট্রাকচারের মাধ্যমে হয়, তাই এগুলি ব্যবহার করার আগে স্ট্রাকচারে অনুমতি দিতে হবে।
কোনও স্ট্রাকচারের জন্য অনুমতি দেওয়া হয়ে গেলে, আপনার অ্যাপে এইসব প্যাকেজ ইমপোর্ট করুন:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
স্ট্রাকচারে নিম্নলিখিত অটোমেশন-নির্দিষ্ট পদ্ধতি সহ একটি
HasAutomations
ইন্টারফেস থাকে:
| API | বিবরণ |
|---|---|
automations() |
স্ট্রাকচারের সাথে সম্পর্কিত সব অটোমেশনের তালিকা তৈরি করো। শুধুমাত্র Home API-এর মাধ্যমে তৈরি করা অটোমেশনই ফেরত দেওয়া হয়। |
createAutomation(automation) |
কোনও স্ট্রাকচারের জন্য অটোমেশন ইনস্ট্যান্স তৈরি করুন। |
deleteAutomation(automationId) |
কোনও অটোমেশন ইনস্ট্যান্স তার আইডি দিয়ে মুছে দিন। |
অটোমেশন তৈরি করা
Home-এর ইনস্ট্যান্স তৈরি করার পরে এবং ব্যবহারকারীর থেকে অনুমতি পাওয়ার পরে, স্ট্রাকচার ও ডিভাইস পান:
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
তারপর, Automation DSL ব্যবহার করে আপনার অটোমেশনের লজিক নির্ধারণ করুন। Home API-তে,
অটোমেশনকে Automation ইন্টারফেসের মাধ্যমে দেখানো হয়। এই ইন্টারফেসে
প্রপার্টির একটি সেট থাকে:
- নাম ও বিবরণের মতো মেটাডেটা।
- এমন ফ্ল্যাগ যা ইঙ্গিত করে, যেমন, অটোমেশন এক্সিকিউট করা যাবে কিনা।
- অটোমেশনের লজিক থাকা নোডের তালিকা, যাকে
অটোমেশন গ্রাফ বলা হয়, যা
automationGraphপ্রপার্টির মাধ্যমে দেখানো হয়।
automationGraph, ডিফল্ট হিসেবে SequentialFlow ধরনের হয়, যা হল একটি ক্লাস
যেখানে নোডের একটি তালিকা থাকে যা ক্রমিক ক্রমে এক্সিকিউট হয়। প্রতিটি নোড
অটোমেশনের একটি এলিমেন্টকে উপস্থাপন করে, যেমন স্টার্টার, কন্ডিশন বা
অ্যাকশন।
অটোমেশনকে name ও description অ্যাসাইন করুন।
অটোমেশন তৈরি করলে isActive ফ্ল্যাগ ডিফল্ট হিসেবে true হয়ে যায়, তাই আপনি যদি প্রথমে অটোমেশন বন্ধ রাখতে না চান, তাহলে এই ফ্ল্যাগ আলাদা করে সেট করার প্রয়োজন নেই। সেই পরিস্থিতিতে, তৈরি করার সময় ফ্ল্যাগকে false হিসেবে সেট করুন।
DraftAutomation ইন্টারফেস অটোমেশন তৈরি ও ক্রিয়েট করার জন্য ব্যবহার করা হয়,
এবং 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()) }
}
}
অটোমেশন DSL নির্দিষ্ট করা হয়ে গেলে, DraftAutomation ইনস্ট্যান্স তৈরি করতে
createAutomation()
মেথডে এটি পাস করুন:
val createdAutomation = structure.createAutomation(automation)
এখান থেকে, আপনি অটোমেশনের উপর অন্যান্য সব অটোমেশন পদ্ধতি ব্যবহার করতে পারবেন, যেমন
execute(), stop() ও update()।
যাচাইকরণ সংক্রান্ত সমস্যা
অটোমেশন তৈরি করার সময় যাচাইকরণে উত্তীর্ণ না হলে, একটি সতর্কতা বা সমস্যার মেসেজ
সমস্যাটি সম্পর্কে তথ্য প্রদান করে। আরও তথ্যের জন্য, ValidationIssueType রেফারেন্স দেখুন।
এমনকি createAutomation() কোনও ব্যতিক্রম না ঘটিয়ে সম্পূর্ণ হলেও, তৈরি হওয়া অটোমেশন বৈধ বা এক্সিকিউট করার উপযুক্ত নাও হতে পারে। ব্যাকএন্ডে ভুল অটোমেশন ড্রাফ্ট সেভ করার
সুবিধা আছে (যেমন, কোনও ব্যবহারকারী যদি পরিচিত মুখ শনাক্তকরণের মতো প্রয়োজনীয়
সম্মতি না দিয়ে থাকেন অথবা ডিভাইসের ক্ষমতা না থাকে)।
ফেরানো
Automation
ইনস্ট্যান্সে আপনাকে সবসময় isValid যাচাই করতে এবং validationIssues চেক করতে হবে:
val createdAutomation = structure.createAutomation(automation)
if (!createdAutomation.isValid) {
// Iterate through validation issues to identify errors and warnings
for (issue in createdAutomation.validationIssues) {
when (issue.severity) {
ValidationIssueSeverity.ERROR -> {
Log.e(
"Automation",
"Validation error on node ${issue.node}: ${issue.issueType}"
)
// Handle error (for example, prompt the user to enable missing
// consents or device features)
}
ValidationIssueSeverity.WARNING -> {
Log.w(
"Automation",
"Validation warning on node ${issue.node}: ${issue.issueType}"
)
}
else -> {}
}
}
}
কোডের উদাহরণ
এখানে আমরা কিছু কোডের উদাহরণ দিচ্ছি যা Android-এ অটোমেশন ডিজাইন করুন পৃষ্ঠায় বর্ণিত কাল্পনিক অটোমেশনের অংশগুলি প্রয়োগ করতে ব্যবহার করা যেতে পারে।
সহজ অটোমেশন
সকাল ৮:০০টায় ব্লাইন্ড উপরে তোলার অটোমেশন এইভাবে প্রয়োগ করা হতে পারে:
// 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() অপারেশন ব্যর্থ হলে, একটি HomeException হতে পারে। Error
হ্যান্ডেলিং দেখুন।
অটোমেশন বন্ধ করা
stop() পদ্ধতি ব্যবহার করে চালু থাকা অটোমেশন বন্ধ করুন:
createdAutomation.stop()
stop() অপারেশন ব্যর্থ হলে, একটি HomeException হতে পারে। Error
হ্যান্ডেলিং দেখুন।
কোনও স্ট্রাকচারের জন্য অটোমেশনের তালিকা পাওয়া
স্ট্রাকচার লেভেলে অটোমেশনকে সংজ্ঞায়িত করা হয়। স্ট্রাকচারের
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")
]))
নামের মাধ্যমে অটোমেশন পাওয়া
API কল আরও রিফাইন করতে Kotlin-এ
filter()
মেথড ব্যবহার করা যেতে পারে। নামের মাধ্যমে অটোমেশন পেতে, স্ট্রাকচারের অটোমেশন পান এবং অটোমেশনের নামের উপর ফিল্টার করুন:
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 হতে পারে। Error
হ্যান্ডেলিং দেখুন।
অটোমেশনের উপর ডিভাইস মুছে দেওয়ার প্রভাব
কোনও ব্যবহারকারী অটোমেশনে ব্যবহৃত ডিভাইস মুছে দিলে, মুছে দেওয়া ডিভাইস
কোনও স্টার্টার ট্রিগার করতে পারবে না এবং অটোমেশন সেটির থেকে অ্যাট্রিবিউট
পড়তে বা সেটিকে কমান্ড ইস্যু করতে পারবে না। যেমন, কোনও ব্যবহারকারী তার হোম থেকে
OccupancySensorDevice
মুছে দিলে এবং কোনও অটোমেশনের এমন একটি স্টার্টার থাকে যা
OccupancySensorDevice-এর উপর নির্ভর করে, তাহলে সেই স্টার্টার আর অটোমেশন অ্যাক্টিভেট করতে পারবে না।