অটোমেশন এপিআইগুলো অ্যান্ড্রয়েডের হোম এপিআই-এর মাধ্যমে অ্যাক্সেস করা যেতে পারে, কিন্তু যেহেতু এগুলোর এন্ট্রি পয়েন্ট একটি স্ট্রাকচারের মাধ্যমে, তাই ব্যবহারের আগে স্ট্রাকচারটির উপর প্রথমে অনুমতি নিতে হবে।
কোনো কাঠামোর জন্য অনুমতি দেওয়া হয়ে গেলে, এই প্যাকেজগুলি আপনার অ্যাপে ইম্পোর্ট করুন:
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 interface) দ্বারা প্রকাশ করা হয়। এই ইন্টারফেসে কিছু প্রোপার্টি থাকে:
- মেটাডেটা, যেমন নাম এবং বিবরণ।
- ফ্ল্যাগ, যা নির্দেশ করে, উদাহরণস্বরূপ, অটোমেশনটি চালানো যাবে কি না।
- অটোমেশনের লজিক ধারণকারী নোডগুলির একটি তালিকা, যাকে অটোমেশন গ্রাফ বলা হয় এবং যা
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()) }
}
}
অটোমেশন DSL সংজ্ঞায়িত হয়ে গেলে, DraftAutomation ইনস্ট্যান্সটি তৈরি করতে এটি createAutomation() মেথডে পাস করুন:
val createdAutomation = structure.createAutomation(automation)
এখান থেকে আপনি অটোমেশনের উপর অন্যান্য সমস্ত অটোমেশন মেথড ব্যবহার করতে পারবেন, যেমন execute() , stop() , এবং update() ।
বৈধতা ত্রুটি
অটোমেশন তৈরি ভ্যালিডেশন পাস না করলে, একটি সতর্কীকরণ বা ত্রুটি বার্তা সমস্যাটি সম্পর্কে তথ্য প্রদান করে। আরও তথ্যের জন্য, ValidationIssueType রেফারেন্সটি দেখুন।
কোডের উদাহরণ
এখানে আমরা কিছু উদাহরণ কোড উপস্থাপন করছি যা "অ্যান্ড্রয়েডে একটি অটোমেশন ডিজাইন করুন" পৃষ্ঠায় বর্ণিত কাল্পনিক অটোমেশনগুলির অংশবিশেষ বাস্তবায়ন করতে ব্যবহার করা যেতে পারে।
সহজ অটোমেশন
সকাল ৮:০০ টায় পর্দা তুলে দেওয়ার একটি অটোমেশন এইভাবে বাস্তবায়ন করা যেতে পারে:
// 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>>রিটার্ন করে। - এই অবজেক্টটিতে, একটি
DeviceTypeপাস করেgetDevicesOfType()কল করুন।
এনটিটি ফিল্টার স্টার্টার, স্টেট রিডার এবং অ্যাকশনে ব্যবহার করা যেতে পারে।
উদাহরণস্বরূপ, একটি স্টার্টার থেকে যেকোনো অন/অফ লাইট দিয়ে অটোমেশন ট্রিগার করতে:
// 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 থ্রো হতে পারে। ত্রুটি পরিচালনা দেখুন।
একটি অটোমেশন বন্ধ করুন
stop() মেথড ব্যবহার করে একটি চলমান অটোমেশন বন্ধ করুন:
createdAutomation.stop()
stop() অপারেশনটি ব্যর্থ হলে, একটি HomeException থ্রো হতে পারে। ত্রুটি পরিচালনা দেখুন।
একটি কাঠামোর জন্য অটোমেশনগুলির একটি তালিকা পান
অটোমেশনগুলো স্ট্রাকচার লেভেলে সংজ্ঞায়িত করা হয়। অটোমেশনের একটি Flow অ্যাক্সেস করতে স্ট্রাকচারের automations() ফাংশনে Collect ব্যবহার করুন:
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() ` মেথডটি এপিআই কলগুলোকে আরও পরিমার্জিত করতে ব্যবহার করা যায়। নাম দিয়ে কোনো অটোমেশন পেতে, স্ট্রাকচারটির অটোমেশনগুলো নিন এবং অটোমেশনের নামের উপর ভিত্তি করে ফিল্টার করুন:
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 উপর নির্ভরশীল হয়, তাহলে সেই স্টার্টারটি আর অটোমেশনটি সক্রিয় করতে পারবে না।