0Pricing
AI Agents · Ders

Sensör Olaylarına Otomatik Yanıt

Sıcaklık > eşik → uyarı → çalıştırma: aracı güdümlü IoT denetim döngüleri.

Sensör Olaylarına Otomatik Yanıt, CoddyKit'te ücretsiz bir AI Agents dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, AI Agents öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. AI Agents kursu toplamda 4 dersten oluşur.

Olaya Dayalı Otomatik Ajan Yanıtları

Bir sensör bir eşiği aştığında ajan, insan müdahalesi olmadan otomatik olarak yanıt vermelidir. Temel zorluklar şunlardır: hangi eylemin gerçekleştirileceğine karar vermek, aynı olayın yinelenen eylemleri tetiklememesini sağlamak ve ajanın çalıştırıcılara komut yağdırmaması için soğuma süresine uymak.

Eylem İlkelerini Tanımlama

Bir eylem ilkesi, sensör koşullarını ajan yanıtlarıyla eşleştirir. Mantık koduna dokunmadan kolayca okunup değiştirilebilmeleri için ilkeleri bildirimsel olarak tanımlayın. Her ilkenin bir koşulu, önceliği ve bir veya daha fazla eylemi vardır.

ACTION_POLICIES = [
    {
        'name': 'HIGH_TEMP_ALERT',
        'topic': 'sensors/temperature',
        'condition': lambda v: v > 38,
        'priority': 'critical',
        'actions': ['TURN_ON_COOLING', 'ALERT_MAINTENANCE', 'LOG_EVENT']
    },
    {
        'name': 'HIGH_TEMP_WARNING',
        'topic': 'sensors/temperature',
        'condition': lambda v: 35 < v <= 38,
        'priority': 'warning',
        'actions': ['ALERT_MAINTENANCE', 'LOG_EVENT']
    },
    {
        'name': 'LOW_HUMIDITY',
        'topic': 'sensors/humidity',
        'condition': lambda v: v < 30,
        'priority': 'warning',
        'actions': ['TURN_ON_HUMIDIFIER', 'LOG_EVENT']
    }
]

def match_policies(topic: str, value: float) -> list:
    return [
        p for p in ACTION_POLICIES
        if p['topic'] == topic and p['condition'](value)
    ]

if __name__ == '__main__':
    matches = match_policies('sensors/temperature', 39)
    print('Matched policies for temperature=39:')
    for p in matches:
        print(f"  {p['name']} ({p['priority']}): {p['actions']}")

Eylem Kuyruğu

Bir eylem kuyruğu, olay algılama ile eylem yürütmeyi birbirinden ayırır. Olaylar kuyruğa eklenir; bir işleyici bunları kuyruktan alıp yürütür. Bu, MQTT alma döngüsünün engellenmesini önler ve bir eylem başarısız olursa yeniden denemelere olanak tanır.

import queue
import threading
from datetime import datetime

action_queue: queue.Queue = queue.Queue(maxsize=500)

def enqueue_action(action_name: str, context: dict, priority: str = 'normal'):
    item = {
        'action': action_name,
        'context': context,
        'priority': priority,
        'enqueued_at': datetime.utcnow().isoformat()
    }
    try:
        action_queue.put_nowait(item)
        print(f'Enqueued: {action_name}')
    except queue.Full:
        print(f'WARNING: Action queue full, dropping {action_name}')

def action_worker(executor_fn):
    """Run in a background thread, executing actions from the queue."""
    while True:
        item = action_queue.get()
        try:
            executor_fn(item['action'], item['context'])
        except Exception as e:
            print(f'Action failed: {item["action"]} — {e}')
        finally:
            action_queue.task_done()

# Start worker thread:
# worker_thread = threading.Thread(target=action_worker, args=(execute_action,), daemon=True)
# worker_thread.start()

if __name__ == '__main__':
    enqueue_action('TURN_ON_COOLING', {'zone': 'server-room'}, priority='critical')
    enqueue_action('LOG_EVENT', {'msg': 'temperature nominal'})
    print('Queue size:', action_queue.qsize())

Olay Tekilleştirme

Tekilleştirme olmadan, 1 okuma/saniye hızında 10 dakika boyunca 38°C'nin üzerinde kalan bir sıcaklık 600 özdeş olay üretir. Tekilleştirme, aynı (konu, koşul, eylem) birleşiminin bir olay boyunca yalnızca bir kez tetiklenmesini ve koşul ortadan kalktığında sıfırlanmasını sağlar.

class EventDeduplicator:
    def __init__(self):
        # active_events: (topic, policy_name) -> event_start_time
        self._active: dict = {}

    def is_new_event(self, topic: str, policy_name: str) -> bool:
        key = (topic, policy_name)
        return key not in self._active

    def mark_active(self, topic: str, policy_name: str):
        self._active[(topic, policy_name)] = datetime.utcnow()

    def clear_event(self, topic: str, policy_name: str):
        key = (topic, policy_name)
        if key in self._active:
            duration = (datetime.utcnow() - self._active.pop(key)).seconds
            print(f'Event cleared: {policy_name} (lasted {duration}s)')

    def clear_topic_if_normal(
        self, topic: str, value: float, normal_fn
    ):
        if normal_fn(value):
            keys = [k for k in self._active if k[0] == topic]
            for k in keys:
                self.clear_event(k[0], k[1])

dedup = EventDeduplicator()
dedup.mark_active('sensors/temperature', 'HIGH_TEMP_ALERT')
print('New event?', dedup.is_new_event('sensors/temperature', 'HIGH_TEMP_ALERT'))

Soğuma Süresi

Bir olay sona erip yeniden tetiklense bile soğuma süresi, hızlı şekilde yeniden tetiklenmesini önler. Tekilleştirmeyi (koşul sürdüğü sürece bir kez tetikle) soğuma süresiyle (koşul ortadan kalktıktan sonra aynı uyarının yeniden tetiklenmesine izin vermeden önce N dakika bekle) birleştirin.

from datetime import datetime, timedelta

class CoolDownManager:
    def __init__(self, cool_down_minutes: int = 15):
        self.cool_down = timedelta(minutes=cool_down_minutes)
        self._cleared_at: dict = {}  # (topic, policy) -> cleared_datetime

    def is_in_cool_down(self, topic: str, policy_name: str) -> bool:
        key = (topic, policy_name)
        cleared_at = self._cleared_at.get(key)
        if cleared_at is None:
            return False
        return datetime.utcnow() - cleared_at < self.cool_down

    def record_clear(self, topic: str, policy_name: str):
        self._cleared_at[(topic, policy_name)] = datetime.utcnow()

    def time_remaining(self, topic: str, policy_name: str) -> int:
        key = (topic, policy_name)
        cleared_at = self._cleared_at.get(key)
        if cleared_at is None:
            return 0
        elapsed = datetime.utcnow() - cleared_at
        remaining = self.cool_down - elapsed
        return max(0, int(remaining.total_seconds()))

cooldown = CoolDownManager(cool_down_minutes=15)
cooldown.record_clear('sensors/temperature', 'HIGH_TEMP_ALERT')
print('In cool-down?', cooldown.is_in_cool_down('sensors/temperature', 'HIGH_TEMP_ALERT'))

LLM Destekli Eylem Kararı

Birden çok eş zamanlı uyarı, çelişen ilkeler veya alışılmadık okuma birleşimleri gibi karmaşık durumlarda kararı LLM'ye devredin. LLM, sensör bağlamının tamamını alır ve önceliklendirilmiş bir eylem planı önerir.

import anthropic
import json

def llm_decide_actions(
    sensor_readings: dict,
    active_policies: list
) -> list:
    client = anthropic.Anthropic(api_key='YOUR_API_KEY')
    context = json.dumps({
        'readings': sensor_readings,
        'triggered_policies': [p['name'] for p in active_policies]
    }, indent=2)
    prompt = (
        f'Current sensor state:\n{context}\n\n'
        'Multiple alert policies are active. '
        'Recommend an ordered list of actions to take. '
        'Consider conflicting effects (e.g., humidifier and cooling may conflict).\n'
        'Return JSON: {"recommended_actions": [str], "reasoning": str}'
    )
    response = client.messages.create(
        model='claude-opus-4-5', max_tokens=512,
        messages=[{'role': 'user', 'content': prompt}]
    )
    return json.loads(response.content[0].text)

Eylemleri MQTT Üzerinden Yürütme

Eylemler, cihaza özgü MQTT konularına komut mesajları yayımlanarak yürütülür. Komut yükü standart bir şemayı izler: eylem adı, parametreler, onay için istek kimliği ve TTL (cihaz çok uzun süre çevrimdışı kalırsa komutun süresi dolar).

import json
import uuid
from datetime import datetime, timedelta

ACTION_TOPICS = {
    'TURN_ON_COOLING': 'devices/hvac/commands',
    'TURN_OFF_COOLING': 'devices/hvac/commands',
    'TURN_ON_HUMIDIFIER': 'devices/humidifier/commands',
    'ALERT_MAINTENANCE': 'notifications/maintenance',
    'LOG_EVENT': 'logs/agent_events'
}

def execute_action(action_name: str, context: dict, mqtt_client) -> str:
    topic = ACTION_TOPICS.get(action_name)
    if not topic:
        print(f'No topic defined for action: {action_name}')
        return 'unknown_action'

    request_id = str(uuid.uuid4())[:8]
    ttl = (datetime.utcnow() + timedelta(minutes=5)).isoformat()
    payload = json.dumps({
        'action': action_name,
        'request_id': request_id,
        'context': context,
        'ttl': ttl
    })
    mqtt_client.publish(topic, payload, qos=1)
    print(f'Executed {action_name} -> {topic} (req={request_id})')
    return request_id

if __name__ == '__main__':
    class FakeMQTT:
        def publish(self, topic, payload, qos=1):
            pass

    execute_action('TURN_ON_COOLING', {'zone': 'server-room'}, FakeMQTT())

Eylem Onayı

Cihazlar, alınan komutları bir onay konusuna yayımlayarak onaylamalıdır. Ajan onay konularına abone olur ve bir zaman aşımı süresi içinde onay alınmazsa yeniden deneyebilir.

import threading
from collections import defaultdict

class AckTracker:
    def __init__(self, timeout_seconds: int = 30):
        self.timeout = timeout_seconds
        self._pending: dict = {}  # request_id -> {'action', 'send_time', 'ack_event'}

    def register(self, request_id: str, action_name: str):
        event = threading.Event()
        self._pending[request_id] = {
            'action': action_name,
            'send_time': datetime.utcnow(),
            'ack_event': event
        }
        # Schedule timeout check
        t = threading.Timer(self.timeout, self._on_timeout, args=[request_id])
        t.daemon = True
        t.start()

    def acknowledge(self, request_id: str):
        entry = self._pending.pop(request_id, None)
        if entry:
            entry['ack_event'].set()
            print(f'Ack received for {entry["action"]} (req={request_id})')

    def _on_timeout(self, request_id: str):
        if request_id in self._pending:
            action = self._pending.pop(request_id)['action']
            print(f'TIMEOUT: No ack for {action} (req={request_id}) — retry?')

Tam Sensör Olayı İşlem Hattı

Tüm bileşenlerin bir araya getirilmesi: MQTT alımı → ilke eşleştirme → tekilleştirme + soğuma denetimi → eylemleri kuyruğa alma → işleyicinin MQTT yayımlamasıyla yürütmesi → onay izleme. Bu mimari, engelleme yapmadan dakikada binlerce sensör olayını işler.

class IoTAgentPipeline:
    def __init__(self, mqtt_client):
        self.mqtt = mqtt_client
        self.dedup = EventDeduplicator()
        self.cooldown = CoolDownManager(cool_down_minutes=15)
        self.ack_tracker = AckTracker(timeout_seconds=30)

    def on_sensor_message(self, topic: str, value: float):
        policies = match_policies(topic, value)
        self.dedup.clear_topic_if_normal(
            topic, value,
            normal_fn=lambda v: v <= 35  # below warning threshold
        )

        for policy in policies:
            name = policy['name']
            if not self.dedup.is_new_event(topic, name):
                continue  # already active, skip
            if self.cooldown.is_in_cool_down(topic, name):
                print(f'In cool-down: {name}')
                continue

            self.dedup.mark_active(topic, name)
            ctx = {'topic': topic, 'value': value, 'policy': name}
            for action in policy['actions']:
                enqueue_action(action, ctx, policy['priority'])

Üst Makama Bildirim Yolu

Bazı durumlar insanlara bildirim gönderilmesini gerektirir: bir komutun onaylanması için yinelenen başarısızlıklar, devam eden kritik koşullar veya birden çok çelişen ilke. Anlık bildirim gönderen ya da bir destek talebi oluşturan bir bildirim yolu tanımlayın.

import requests

def escalate_to_human(
    reason: str,
    sensor_data: dict,
    webhook_url: str = 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
):
    message = {
        'text': (
            f'*IoT Agent Escalation* \n'
            f'Reason: {reason}\n'
            f'Sensor data: {sensor_data}\n'
            f'Time: {datetime.utcnow().isoformat()}'
        )
    }
    try:
        response = requests.post(webhook_url, json=message, timeout=5)
        response.raise_for_status()
        print(f'Escalation sent: {reason}')
    except requests.RequestException as e:
        print(f'Escalation failed: {e}')
        # Fall back: log to file
        with open('escalations.log', 'a') as f:
            import json
            f.write(json.dumps({'reason': reason, 'data': sensor_data}) + '\n')

Olay İşlem Hattını Sınama

Olay işlem hattınızı üretime almadan önce sensör olaylarını benzeten ve doğru eylemlerin kuyruğa alındığını doğrulayan otomatik sınamalar yazın. Her ilkeyi ayrı ayrı, tekilleştirme davranışını ve soğuma süresinin dolmasını sınayın.

import time

def test_high_temp_policy_fires_once():
    dedup = EventDeduplicator()
    cooldown = CoolDownManager(cool_down_minutes=0)  # disable cooldown for test
    pipeline = IoTAgentPipeline(None)
    pipeline.dedup = dedup
    pipeline.cooldown = cooldown

    actions_fired = []
    action_queue.queue.clear()

    # Fire same event 5 times in a row
    for _ in range(5):
        pipeline.on_sensor_message('sensors/temperature', 40.0)

    # Only 1 set of actions should have been enqueued
    actions = list(action_queue.queue)
    assert len(actions) > 0, 'At least one action should fire'
    print(f'Actions enqueued: {len(actions)} (expected: just 1 event worth)')
    return True

result = test_high_temp_policy_fires_once()
print('Test passed:', result)

Bilgi Kontrolü

Bir sensör olay işlem hattında olay tekilleştirmenin temel amacı nedir?

Özet: Sensör Olaylarına Otomatik Yanıt

Harika! Öğrendikleriniz:

  • Eylem ilkeleri: önceliklere sahip bildirimsel koşuldan eyleme eşleme
  • Eylem kuyruğu: algılamayı yürütmeden ayırır; iş parçacığı eylemleri işler
  • Tekilleştirme: okuma başına değil, olay başına bir kez tetikleme
  • Soğuma süresi: koşul ortadan kalktıktan hemen sonra yeniden tetiklenmeyi önleme
  • LLM'ye bildirim: karmaşık, çok ilkeli durumları LLM'nin değerlendirmesine devretme
  • Onay izleme: onaylanmayan komutları algılama ve yeniden deneme

Sırada: Raspberry Pi gibi uç cihazlara hafif ajanları dağıtma.

Sıkça Sorulan Sorular

“Sensör Olaylarına Otomatik Yanıt” dersi ücretsiz mi?

Evet — “Sensör Olaylarına Otomatik Yanıt” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve AI Agents kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. AI Agents kursu toplamda 4 dersten oluşur.

“Sensör Olaylarına Otomatik Yanıt” dersinde ne öğreneceğim?

Sıcaklık > eşik → uyarı → çalıştırma: aracı güdümlü IoT denetim döngüleri. AI Agents ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

AI Agents öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te AI Agents, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.

“Sensör Olaylarına Otomatik Yanıt” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu AI Agents dersinde kod yazıp çalıştırabilir miyim?

Evet. Her AI Agents dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Aracı Entegrasyonu İçin MQTT Protokolü
  2. Aracılarda Zaman Serisi Verisi İşleme
  3. Sensör Olaylarına Otomatik Yanıt
  4. Hafif Aracıların Uçta Dağıtımı
← AI Agents Sayfasına Dön