# Proje yazma

Projeler kartta `/projects` (SD varsa `/sd/projects`) altında yaşar. Her proje tek bir `.py` dosyasıdır, `import cyd` ile kartın donanımına ve çalışma ortamına erişir. Aynı dosya üç kartta da çalışır; kartta olmayan donanım açık hata fırlatır, sessizce yanlış çalışmaz.

## İskelet

```python
import cyd
from machine import Pin

led = Pin(getattr(cyd, 'D1', 22), Pin.OUT, value=0)   # NodeMCU: D1, CYD: GPIO22

try:
    while not cyd.should_stop():      # paneldeki Durdur'u dinle
        led.value(1)
        if not cyd.sleep(0.5): break  # durdurulabilir bekleme (saniye)
        led.value(0)
        if not cyd.sleep(0.5): break
finally:
    led.value(0)                      # nasil biterse bitsin temizle
```

## Durdurma sözleşmesi

- `while True` değil, `while not cyd.should_stop()`. `should_stop()` global olarak da enjekte edilir.
- `time.sleep` değil, `cyd.sleep(sn)`: beklerken Durdur'u dinler, kesilirse `False` döner, komşu projelere sıra verir. Normal modda otomatik `await`'e çevrilir.
- Dinleyen proje 3 saniye içinde temiz çıkar. Dinlemeyen normal görev iptal edilir (`finally` çalışır). Hiç bekleme yapmayan proje ortak çalışanı kilitler; 5 saniye sonra kart resetlenir (panel bu sırada cevap verir). Thread'de: tek çalışan oysa reset, başkaları varsa "takıldı" işareti ve zorla düğmesi.
- `print()` panele ve `/logs/<proje>.log` dosyasına akar; solo modda da kaybolmaz.

## `cyd` modülü

| Çağrı | Ne yapar |
|---|---|
| `cyd.should_stop()` · `cyd.sleep(sn)` | Durdurma sözleşmesi |
| `cyd.display(rot=None, bgr=None)` | Ekran (tembel oluşturulur; `fill`, `fill_rect`, `text(..., olcek)`, `circle`). OLED'de aynı API, renkler yanık/sönük'e düşer |
| `cyd.touch()` | `.touch()` → `(x, y)` ya da `None`, `.pressed()`, `.raw()` |
| `cyd.set_display(rot, bgr)` · `cyd.test_pattern()` | Yön ayarı |
| `cyd.led(r, g, b)` · `cyd.led_off()` | Kart üstü RGB LED (ters mantık) |
| `cyd.light()` | LDR, 0–4095 (büyük = karanlık) |
| `cyd.beep(freq, ms)` | Hoparlör (GPIO 26) |
| `cyd.buton(pin, fn=None, aktif=0, sekme_ms=40)` | Kesme tabanlı buton: `.basildi()` (tüketir), `.sayac`, `.basili()`; proje bitince kesme kapanır |
| `cyd.rota('/yol', fn)` · `cyd.rota_sil()` · `cyd.rotalar()` | Projenin web sayfası, ana sunucuda |
| `cyd.dram()` | Boş dahili DRAM (bayt); BLE/TLS öncesi buna bak |
| `cyd.wifi()` | Bağlı STA arayüzü (yalnız kullan, kapatma) |
| `cyd.mount_sd()` | SD'yi `/sd` altına bağlar, yolu döner ya da `None` |
| `cyd.claim_display()` | `(True, None)` ya da `(False, 'sahip proje')` |
| `cyd.job_name()` | Bu projenin adı |
| `cyd.D0` … `cyd.D8`, `cyd.A0` | NodeMCU pin etiketleri |

## Projenin kendi web sayfası

İkinci bir HTTP sunucusu açma. Ana sunucu `/api` dışı her isteği önce projelerin kaydettiği rotalara bakar: tek soket, tek döngü, aynı port.

```python
import cyd

sayac = 0

def sayfa(istek):                 # istek: {'yontem', 'yol', 'sorgu', 'govde'}
    global sayac
    sayac += 1
    return '<h1>merhaba %d</h1>' % sayac   # str -> html, dict/list -> json,
                                           # bytes -> ham, (durum, tip, govde) -> ozel
cyd.rota('/selam', sayfa)

while not cyd.should_stop():
    cyd.sleep(1)
```

İşleyici sunucunun iş parçacığında koşar: kısa tut, içinde `cyd.sleep` bekleme, paylaşılan durumu basit değişkenlerde tut. Proje bitince rotaları kendiliğinden silinir. Panelde **Uygulamalar** satırında bağlantı olarak görünür. Örnek: `yuk_kontrol.py` (`http://<ip>/yuk`).

## Buton: yoklama değil kesme

```python
import cyd

b = cyd.buton(22)                 # GPIO22 <-> GND
while not cyd.should_stop():
    if b.basildi():
        print('basildi', b.sayac)
    cyd.sleep(0.05)
```

Ölçüldü (50 taklit basış, ekran çizen proje ve ağır thread yanında): 10 ms yoklama 5/50 yakaladı, kesme **50/50**.

## Yapılmayacaklar

- **İkinci HTTP sunucusu açma.** İkinci dinleyici soket lwIP tamponlarıyla dahili DRAM'i tüketip paneli kilitledi (ölçüldü). `cyd.rota` kullan.
- **`wlan.active(False)` / `wlan.disconnect()` çağırma.** Paneli de düşürür.
- **`machine.reset()` çağırma.** `jobs` zaten yönetiyor.
- **Sleep'siz sonsuz döngü yazma.** Normal modda komşuları bekletir, thread'de Durdur reset atar.
- **Ekranı iki projeden çizme.** Veri bozulmaz (SPI kilidi var) ama üst üste çizerler; `cyd.claim_display()` sahipliği bildirir.

## Ağ

| Yöntem | Normal mod | Solo mod |
|---|---|---|
| `requests.get('http://...')` | ✅ | ✅ |
| `requests.get('https://...')` | ❌ ENOMEM | ✅ |
| Ham `socket` | ✅ | ✅ |
| `ntptime.settime()` | ✅ | ✅ |
| BLE (`bluetooth`) | ❌ EIO | ✅ |

`requests` gövdeyi RAM'e alır; büyük dosyayı ham soketle parça parça gönder (`ornek_sunucuya_yukle.py`, 22 KB DRAM ile 9690 bayt doğrulandı). Olmayanlar: kamera modülü, WireGuard, Node.js / C#.

## NodeMCU'da dikkat

RAM az (panel açıkken ~24 KB). Uzun `print` metinlerinden kaçın; büyük kütüphaneleri önceden derlenmiş `.mpy` olarak koy (`mpy-cross bme280.py`), kaynak `.py` import edilirken ayrıştırma için büyük geçici blok ister ve `MemoryError` verir.
