Skip to content

BurakBoz/esp-ai-hid

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI HID Controller v3.0

License: CC BY 4.0

USB HID (Human Interface Device) sınıfından bir donanım üzerinden bilgisayarın klavye ve fare arayüzünü AI ile kontrol etmek için geliştirilmiş açık kaynak proje.

ESP32-S2 Lolin Mini'yi USB klavye + fare olarak kullanan firmware, CRC32 doğrulamalı seri protokol ve Python client kütüphanesi. Yapay zeka ajanlarının fiziksel bilgisayarları gerçek HID cihazı üzerinden otonom olarak kullanmasını sağlar.

Anahtar Kelimeler: USB HID, Human Interface Device, ESP32-S2, AI computer use, keyboard emulator, mouse emulator, hardware automation, keystroke injection, TinyUSB, Arduino, Python serial, CRC32 protocol, Turkish keyboard layout, TR-Q, ISO/ANSI, device spoofing, VID/PID, penetration testing, red team, physical access, USB rubber ducky alternative, BadUSB, HID attack, automation framework, ESP32 keyboard mouse, USB gadget, human typing simulation

Bu Ne İşe Yarar?

Kartı bilgisayarına USB ile takıyorsun. Bilgisayar bunu gerçek bir klavye ve fare olarak görüyor. Sonra Python ile komut gönderiyorsun — kart o komutları klavye/fare hareketi olarak bilgisayara iletiyor.

Kısa versiyon:

from client.aihid_client import AIHIDClient

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.text("Merhaba Dünya!")     # bilgisayara "Merhaba Dünya!" yazar
    hid.combo("KEY_LEFT_CTRL", "c") # Ctrl+C basar
    hid.mouse(100, 0)              # fareyi 100px sağa hareket ettirir
    hid.click("L")                 # sol tıklama yapar

Dosya Yapısı

esp_ai_hid/
├── aihid_firmware/              ← Arduino sketch (IDE uyumlu)
│   ├── aihid_firmware.ino       ← ESP32 firmware
│   ├── BOARD_CONFIG.md          ← Flash layout, NVS, pin detayları
│   └── data/
│       └── EspTinyUSB-master.zip
├── client/
│   ├── aihid_client.py          ← Python client kütüphanesi
│   └── demos/
│       └── safari_search.py     ← Safari + Google arama demosu
├── tests/
│   ├── conftest.py              ← pytest ayarları + marker'lar
│   └── test_aihid.py            ← Test paketi (72 unit + 22 integration)
├── requirements.txt
└── README.md                    ← Bu dosya

1. Donanım Kurulumu

Gerekli Malzemeler

  • 1x Lolin S2 Mini (ESP32-S2 tabanlı)
  • 1x USB-C kablo
  • Bilgisayar (macOS, Windows, Linux)

Arduino IDE Kurulumu

  1. Arduino IDE 2.x indir ve kur.

  2. ESP32 board paketini ekle:

    • File → Preferences → Additional Board Manager URLs kısmına yapıştır:
      https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
      
    • OK tıkla.
  3. Board paketini kur:

    • Tools → Board → Boards Manager
    • esp32 ara
    • espressif olanını kur (sürüm 3.x)
  4. Board ayarlarını yap (Tools menüsü):

    Ayar Değer
    Board LOLIN S2 Mini
    USB CDC On Boot Disabled
    USB Mode USB-OTG (TinyUSB)
    Core Debug Level None
    USB DFU On Boot Disabled
    Erase All Flash Before Upload Disabled
    USB Firmware MSC On Boot Disabled
    Partition Scheme Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
    Upload Speed 921600
    CPU Frequency 240MHz

    USB CDC On Boot = Disabled çok önemli. Enabled olursa USB stack kodundan önce başlar ve VID/PID/isim değiştirme çalışmaz. Bunu yanlış ayarlaman en sık karşılaşılan sorun.

    Detaylı flash layout, NVS şeması ve pin bilgileri: aihid_firmware/BOARD_CONFIG.md

Firmware Yükleme

  1. aihid_firmware/aihid_firmware.ino dosyasını Arduino IDE'de aç.
  2. Kartı USB ile bilgisayara bağla.
  3. Port'u seç: Tools → Port → (kartın portu).
  4. Upload butonuna bas.
  5. Eğer kart otomatik boot moduna girmezse:
    • 0 butonuna basılı tut
    • RST butonuna bas
    • 0 butonunu bırak
    • Tekrar Upload'a bas
  6. Yükleme bittikten sonra USB kablosunu çıkar.
  7. Farklı bir USB portuna tekrar tak.
  8. Yeni bir serial port oluşacak — o portu not et.

İlk yüklemeden sonra USB'yi çıkarıp takmak ZORUNLU. Çünkü USB descriptor'lar sadece boot sırasında yükleniyor.

Doğrulama

macOS:

system_profiler SPUSBDataType | grep -A5 "AI"

Şunu görmelisin:

AI Keyboard + Mouse:
  Manufacturer: AI Controller
  USB Vendor ID: 0x303a
  USB Product ID: 0x00ab01

Linux:

lsusb | grep 303a

Windows: Aygıt Yöneticisi → USB cihazları


2. Python Client Kurulumu

Gereksinimler

pip install pyserial

Başka bir şey gerekmez. client/aihid_client.py tek dosya, bağımlılığı sadece pyserial.

Linux: Fare pozisyon algılama (opsiyonel)

get_mouse_position() ve move_to(from_corner=False) kullanacaksan:

# X11 (Arch / CachyOS)
sudo pacman -S xdotool

# X11 (Ubuntu / Debian)
sudo apt install xdotool

# Wayland — KDE
sudo pacman -S kdotool       # veya: pip install kdotool

# Wayland — Genel (sway, GNOME, vb.)
sudo pacman -S ydotool

xdotool/kdotool/ydotool yüklü değilse move_to() otomatik olarak köşe reset'e (from_corner=True) düşer — pozisyon algılama aracı gerekmez. Yalnızca from_corner=False modunda hızlı delta hareketi için gereklidir.

Algılama zinciri: X11 → xdotool | Wayland → kdotoolydotool | macOS → Quartz | Windows → GetCursorPos

Ekran çözünürlüğü algılama (get_screen_resolution()) X11'de xrandr, Wayland'da swaymsg kullanır — bunlar genelde önyüklüdür.

Bağlantı

from client.aihid_client import AIHIDClient

# Otomatik port tespiti (VID/PID ile cihazı bulur)
hid = AIHIDClient()

# veya manuel port
hid = AIHIDClient("/dev/tty.usbmodem1101")

# İşin bitince kapat
hid.disconnect()

Veya with bloğu ile (önerilen):

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.ping()
    # ... işlemler ...
# Blok bitince otomatik kapanır

Port Bulmak

macOS:

ls /dev/tty.usbmodem*

Linux:

ls /dev/ttyACM*

Windows:

Aygıt Yöneticisi → Bağlantı Noktaları (COM ve LPT) → COMxx

3. Komutlar

Metin Yazma

hid.text("Merhaba Dünya!")

Bilgisayarda imleç neredeyse oraya yazar. Türkçe karakterler (ğ, ü, ş, ı, ö, ç ve büyük halleri) desteklenir.

Yeni satır:

hid.text("Satır 1\\nSatır 2\\nSatır 3")
# veya
hid.text("Satır 1{ENTER}Satır 2{ENTER}Satır 3")

Tab:

hid.text("Sütun1\\tSütun2\\tSütun3")
# veya
hid.text("Sütun1{TAB}Sütun2{TAB}Sütun3")

Yazı arasında bekleme:

hid.text("[email protected]{TAB}{DELAY:500}SuperSifre123{ENTER}")

Bu ne yapar:

  1. E-posta yazar
  2. Tab'a basar (şifre alanına geçer)
  3. 500ms bekler (sayfa animasyonu için)
  4. Şifreyi yazar
  5. Enter'a basar

{DELAY:ms} — milisaniye cinsinden bekleme. Max 30000 (30 saniye). Negatif değer 0'a clamp edilir.

TEXT içinde tuş basımı:

# Yanlış yazdın, düzelt
hid.text("yanlsi{K:KEY_BACKSPACE:2}ış")
# yanlış → "yanlış" (2 karakter siler, doğrusunu yazar)

# Ok tuşlarıyla gezin
hid.text("metin{K:KEY_LEFT:3}ek")
# "metin" yaz → 3 sola git → "ek" yaz → "meetkinn" değil "meetkinn"

# Tek tuş
hid.text("satır1{K:KEY_RETURN}satır2")

# Escape tuşu
hid.text("{K:KEY_ESCAPE}")

{K:TUŞ_ADI} — tek basım. {K:TUŞ_ADI:N} — N kere tekrar (max 255). Tüm tuş isimleri (bkz. Bölüm 12) desteklenir.

Escape Açıklama
{K:KEY_BACKSPACE} 1x Backspace
{K:KEY_BACKSPACE:5} 5x Backspace
{K:KEY_LEFT:3} 3x Sol ok
{K:KEY_DELETE} 1x Delete
{K:KEY_HOME} Satır başı
{K:KEY_END} Satır sonu
{K:KEY_ESCAPE} ESC
{K:KEY_F5} F5 (yenile)
{K:KEY_RETURN} Enter (= {ENTER})
{K:KEY_UP:10} 10x Yukarı ok

Backslash yazmak:

hid.text("C:\\\\Users\\\\Desktop")  # Python'da \\\\ gerekli

Tek Karakter

hid.key("A")
hid.key("5")
hid.key("ğ")

Özel Tuş Basma

hid.press("KEY_RETURN")      # Enter
hid.press("KEY_TAB")         # Tab
hid.press("KEY_BACKSPACE")   # Backspace
hid.press("KEY_ESCAPE")      # Escape
hid.press("KEY_F5")          # F5
hid.press("KEY_DELETE")      # Delete
hid.press("KEY_UP")          # Yukarı ok
hid.press("KEY_DOWN")        # Aşağı ok
hid.press("KEY_LEFT")        # Sol ok
hid.press("KEY_RIGHT")       # Sağ ok
hid.press("KEY_HOME")        # Home
hid.press("KEY_END")         # End

Kısayol Tuşları

hid.combo("KEY_LEFT_CTRL", "c")                              # Ctrl+C (kopyala)
hid.combo("KEY_LEFT_CTRL", "v")                              # Ctrl+V (yapıştır)
hid.combo("KEY_LEFT_CTRL", "a")                              # Ctrl+A (tümünü seç)
hid.combo("KEY_LEFT_CTRL", "z")                              # Ctrl+Z (geri al)
hid.combo("KEY_LEFT_ALT", "KEY_TAB")                         # Alt+Tab (pencere değiştir)
hid.combo("KEY_LEFT_ALT", "KEY_F4")                          # Alt+F4 (pencereyi kapat)
hid.combo("KEY_LEFT_GUI", "KEY_SPACE")                       # Cmd+Space (macOS Spotlight)
hid.combo("KEY_LEFT_CTRL", "KEY_LEFT_SHIFT", "KEY_ESCAPE")   # Ctrl+Shift+Esc (Görev Yöneticisi)

KEY_LEFT_GUI = Windows tuşu / macOS Command tuşu.

Tuşu Basılı Tutma

hid.hold("KEY_LEFT_SHIFT")   # Shift'i basılı tut
hid.press("KEY_RIGHT")       # Sağa git (seçim yapar)
hid.press("KEY_RIGHT")
hid.press("KEY_RIGHT")
hid.release("KEY_LEFT_SHIFT") # Shift'i bırak
hid.combo("KEY_LEFT_CTRL", "c")  # Seçili metni kopyala

Fare Hareket

hid.mouse(100, 0)      # 100 piksel sağa
hid.mouse(-100, 0)     # 100 piksel sola
hid.mouse(0, 100)      # 100 piksel aşağı
hid.mouse(0, -100)     # 100 piksel yukarı
hid.mouse(50, 50)      # çapraz (sağ-aşağı)

İlk sayı = yatay (+ sağ, - sol). İkinci sayı = dikey (+ aşağı, - yukarı). Max ±10000 piksel. Büyük hareketler otomatik küçük adımlara bölünür.

Tıklama

hid.click("L")    # Sol tıklama
hid.click("R")    # Sağ tıklama
hid.click("M")    # Orta tıklama (scroll tuşu)

Çift Tıklama

hid.dblclick("L")   # Sol çift tıklama
hid.dblclick("R")   # Sağ çift tıklama

İki tıklama arasında 60-100ms rastgele gecikme — gerçek insan gibi görünür.

Scroll

hid.wheel(3)     # 3 birim aşağı scroll
hid.wheel(-3)    # 3 birim yukarı scroll

Max ±127.

Sürükle-Bırak

Göreceli sürükleme — mevcut konumdan:

hid.drag(200, 0)      # 200px sağa sürükle
hid.drag(0, 100)      # 100px aşağı sürükle
hid.drag(-100, -50)   # sol-yukarı sürükle

Sol tuşu basar → hareket eder → bırakır.

İki nokta arası sürükle-bırak:

hid.dragto(100, 200, 400, 200)
# (100,200) noktasına git → sol tuş bas → (400,200)'e sürükle → bırak

Manuel sürükleme bırakma:

hid.dragrel()   # Yarım kalan sürüklemeyi bırak

Release (Bırakma)

hid.release()               # HER ŞEYİ bırak (klavye + fare)
hid.release("KB")           # Sadece klavye
hid.release("MOUSE")        # Sadece fare
hid.release("L")            # Sol fare butonu
hid.release("R")            # Sağ fare butonu
hid.release("M")            # Orta fare butonu
hid.release("KEY_LEFT_SHIFT")  # Tek tuş

Bir şeyler sıkıştıysa (tuş basılı kaldı, fare takıldı): hid.release() çağır. Her şeyi sıfırlar.

Mutlak Fare Pozisyonu

Fareyi ekran üzerinde belirli bir koordinata veya köşeye götürür. Herhangi bir çözünürlükte (8K/16K dahil) çalışır.

from client.aihid_client import get_screen_resolution, get_mouse_position

# Ekran çözünürlüğü ve fare pozisyonu algıla
w, h = get_screen_resolution()       # (3840, 2160)
x, y = get_mouse_position()          # (512, 384)

# Köşeye git
hid.move_to_corner("top-left")       # Sol üst (0, 0)
hid.move_to_corner("bottom-right")   # Sağ alt

# Mutlak koordinata git
hid.move_to(960, 540)                # Önce köşeye reset, sonra hedefe
hid.move_to(1200, 800, from_corner=False)  # Mevcut pozisyondan delta (hızlı)

# Pozisyon takibi
print(hid.mouse_pos)                 # (1200, 800)
print(hid.screen_size)               # (3840, 2160)

İnsansı Fare Hareketi

HumanMouseConfig ile WindMouse veya Bézier algoritmasıyla gerçek insana benzeyen fare hareketi:

from client.aihid_client import HumanMouseConfig

# Varsayılan — WindMouse, hızlı + insansı
hid.move_to(960, 540, humanize=True)

# Tam kontrol
cfg = HumanMouseConfig(
    algorithm="wind",        # "wind" veya "bezier"
    speed=1.8,               # Hız çarpanı (0.5=yavaş, 3.0=hızlı)
    gravity=12.0,            # Hedefe çekim (yüksek=hızlı yakınsama)
    wind=4.0,                # Rastgele sapma (doğal eğri)
    overshoot_threshold=300, # Bu mesafeden büyükse overshoot yap
    overshoot_radius=0.03,   # Overshoot mesafesi (oransal)
    jitter=0.8,              # El titremesi (piksel)
)
hid.move_to(1500, 900, from_corner=False, human_config=cfg)

Algoritmalar:

Algoritma Açıklama En İyi Kullanım
wind WindMouse: fizik tabanlı (yerçekimi + rüzgar). Doğal overshoot, sapma, yavaşlama. Genel kullanım, en gerçekçi
bezier Kübik Bézier eğrisi + easing. Öngörülebilir, yumuşak hareket. Kısa mesafe, UI etkileşimi

Hız profilleri:

# Yavaş ve çok doğal
cfg = HumanMouseConfig(speed=0.5, jitter=1.5)

# Varsayılan — hızlı ama insansı
cfg = HumanMouseConfig()  # speed=1.8

# Çok hızlı — robot/insan arası
cfg = HumanMouseConfig(speed=3.0, jitter=0.3, overshoot_radius=0)

# Bézier — yumuşak eğri
cfg = HumanMouseConfig(algorithm="bezier", easing="ease-in-out", speed=1.2)

Ekran sınırı koruması: Hiçbir parametre kombinasyonu fareyi ekran dışına çıkaramaz. Tüm ara adımlar ekran sınırlarına kırpılır.


4. Ayarlar

Tüm ayarlar cihazın kalıcı belleğine (NVS) kaydedilir. Güç kesilse bile hatırlanır.

Klavye Dili

hid.set_lang("TR")    # Türkçe-Q layout (varsayılan)
hid.set_lang("US")    # US English layout

Anında geçerli olur, reboot gerekmez.

Önemli: Bilgisayarında da aynı layout seçili olmalı. macOS: System Settings → Keyboard → Input Sources → Turkish-Q

Klavye Tipi

hid.set_kb("ISO")     # macOS (varsayılan)
hid.set_kb("ANSI")    # Windows/Linux

macOS ISO klavyelerde " ve < tuşları yer değiştirir. macOS kullanıyorsan ISO'da bırak.

İnsansı Yazım

hid.set_human(True)    # İnsansı gecikme açık (varsayılan)
hid.set_human(False)   # Robot hızında yaz

Açıkken her tuş arası rastgele gecikme eklenir. Doğal görünür.

Gecikme ayarları:

# Normal harf arası: min-max ms
hid.set_typing_delay(30, 120)

# Noktalama/boşluk sonrası: min-max ms
hid.set_punctuation_delay(200, 500)

Profil örnekleri:

# Yavaş — daktilo hissi
hid.set_typing_delay(80, 200)
hid.set_punctuation_delay(400, 800)

# Hızlı — ama yine insansı
hid.set_typing_delay(10, 35)
hid.set_punctuation_delay(50, 150)

# Robot — en hızlı
hid.set_human(False)

USB Cihaz Bilgileri

Bilgisayar USB cihazını bu bilgilerle tanır. Değiştirebilirsin:

hid.set_vid(0x046D)                   # Vendor ID (örn: Logitech)
hid.set_pid(0xC31C)                   # Product ID
hid.set_manufacturer("Logitech")      # Üretici ismi
hid.set_product("Logitech Keyboard")       # Ürün ismi
hid.set_serial("ABC123")              # Seri numarası
hid.reboot()                          # DEĞİŞİKLİKLER REBOOT SONRASI GEÇERLİ!

Reboot zorunlu. USB descriptor'lar sadece boot sırasında yükleniyor.

Host OS cache: Bilgisayar eski VID/PID'yi hatırlayabilir. Farklı USB portuna takmayı dene.

Linux uyarı: Logitech Unifying Receiver PID'si (0xC52B) kullanmayın. Linux hid-logitech-dj kernel modülü bu PID'yi yakalar ve özel Logitech protokolü bekler — cihaz HID olarak çalışmaz. Bunun yerine 0xC31C (K120 Keyboard) gibi genel HID sürücüsüne düşen bir PID tercih edin.

Genel SET

hid.set("LANG", "TR")        # Yukarıdaki fonksiyonların alt seviye hali
hid.set("TYPMIN", "50")

5. Sistem Komutları

Bağlantı Testi

if hid.ping():
    print("Cihaz bağlı ve çalışıyor")
else:
    print("Cihaz yanıt vermiyor")

Cihaz Bilgileri

info = hid.getinfo()
print(info["VID"])      # "0x303A"
print(info["PID"])      # "0xAB01"
print(info["MANU"])     # "AI Controller"
print(info["LANG"])     # "TR"
print(info["HEAP"])     # "180000" (kullanılabilir RAM, byte)
print(info["FW"])       # "v3.0"
print(info["PROTO"])    # "1"

Dönen tüm alanlar:

Alan Açıklama
VID USB Vendor ID
PID USB Product ID
MANU Manufacturer ismi
PROD Product ismi
SER Serial numarası
LANG Klavye layout (TR/US)
KB Klavye tipi (ISO/ANSI)
HUMAN İnsansı yazım (ON/OFF)
TYMIN Tuş gecikme min (ms)
TYMX Tuş gecikme max (ms)
TYPN Noktalama gecikme min (ms)
TYPX Noktalama gecikme max (ms)
DRAG Sürükleme aktif mi (YES/NO)
FW Firmware sürümü
PROTO Protokol sürümü
HEAP Boş RAM (byte)
UP Çalışma süresi (saniye)

Komut Listesi

commands = hid.help()
# ['TEXT', 'KEY', 'PRESS', 'COMBO', 'HOLD', 'RELEASE', 'MOUSE', ...]

Yeniden Başlatma

hid.reboot()

USB bağlantısı kopar. Tekrar bağlanmak için:

hid.reboot()
time.sleep(3)
hid.disconnect()
hid = AIHIDClient("/dev/tty.usbmodem1101")
hid.wait_for_boot()

6. Protokol Detayları

Client yazmak isteyenler için. Python dışında bir dilde client yazacaksan bu bölümü oku.

İletişim

  • Fiziksel: USB CDC (sanal serial port), 115200 baud
  • Encoding: UTF-8
  • Satır sonu: \n (LF)
  • Her komut için tam olarak bir response satırı döner

Request Format (Client → Cihaz)

Komut + CRC suffix, \n ile biter:

KOMUT:parametre\x04CRCHEX\n
  • \x04 (EOT) = CRC ayırıcı
  • CRCHEX = komutun CRC32'si (8 hex, uppercase)
  • CRC, komutun kendisi (KOMUT:parametre) üzerinden hesaplanır (suffix hariç)
  • Cihaz CRC'yi doğrular: uyuşmazlıkta ERR rx_crc_mismatch döner
  • CRC suffix opsiyonel — yoksa cihaz eski protokolle (tek yönlü) çalışır

Response Format (Cihaz → Client)

>CRCHEX OK [payload]
>CRCHEX ERR reason
  • > — response satırı başlangıcı
  • CRCHEX — gönderilen komutun CRC32'si, 8 hex karakter, uppercase
  • OK — komut başarılı
  • ERR — komut başarısız, reason = İngilizce hata açıklaması
  • payload — komuta özel ek bilgi (opsiyonel, virgülle ayrılmış key=value)

Sistem Mesajları (Cihaz → Client)

#TAG message
  • # ile başlar, CRC yok
  • Client bunları bilgilendirme olarak loglamalı
  • Bilinen tag'ler:
    • #BOOT — cihaz açıldı, firmware bilgileri
    • #WARN — uyarı (heap düşük, satır kesildi vb.)

CRC32 Hesaplama

Standart CRC32 (IEEE 802.3), komut string'inin UTF-8 byte'ları üzerinde hesaplanır.

Python:

import binascii
crc = binascii.crc32(command.encode('utf-8')) & 0xFFFFFFFF

C:

#include <esp_rom_crc.h>
uint32_t crc = esp_rom_crc32_le(0, (const uint8_t*)cmd, len);

Client Parsing Kuralları

  1. Serial'den satır oku
  2. > ile başlıyorsa → response:
    • İlk 8 hex karakteri çıkar → response CRC
    • Gönderdiğin komutun CRC'si ile karşılaştır
    • Eşleşmiyorsa → CRC hata
    • OK veya ERR oku
    • Payload'ı parse et
  3. # ile başlıyorsa → sistem mesajı, logla
  4. Diğer → görmezden gel

Örnek Oturum

[cihaz açılır]
← #BOOT AI_HID v3.0 PROTO=1 VID=0x303A PID=0xAB01 LANG=TR KB=ISO

→ PING
← >B7B2364B OK PONG

→ TEXT:Merhaba
← >A3F1C2D4 OK bytes=7

→ WHEEL:abc
← >C5B6A7D8 ERR invalid_number

→ SET:VID=0x046D
← >E1D2F3A4 OK VID=0x046D,reboot_required

→ GETINFO
← >D4C3B2A1 OK VID=0x303A,PID=0xAB01,MANU=AI Controller,...

→ REBOOT
← >F1E2D3C4 OK rebooting
[bağlantı kopar]

Hata Kodları (ERR reason)

Reason Açıklama
empty Parametre boş (KEY:, PRESS:, HOLD:)
invalid_char Geçersiz/tanınamayan karakter
invalid_number Sayı parse edilemedi
invalid_button 'X' (L/R/M) Geçersiz fare butonu
invalid_value TR|US Geçersiz değer, kabul edilenler listesi
unknown_key KEY_XYZ Bilinmeyen tuş ismi
unknown_command BLABLA Bilinmeyen komut
unknown_param XYZ Bilinmeyen SET parametresi
unknown_target XYZ Bilinmeyen RELEASE hedefi
empty_value SET değeri boş
too_long max=63 String çok uzun
format MOUSE:dx,dy Yanlış parametre formatı
unsupported U+XXXX Desteklenmeyen Unicode karakter
cmd_too_long len=N max=512 Komut çok uzun
no_valid_keys COMBO'da geçerli tuş yok
heap_low N Yetersiz bellek, komut reddedildi
rx_crc_mismatch Komut iletimde bozuldu (bidirectional CRC)

7. Test

Gereksinimler

pip install pyserial pytest

Unit Testler (cihaz gerekmez)

MockSerial ile firmware davranışını simüle eder. 72 test:

python -m pytest tests/ -v -k unit

Integration Testler (cihaz bağlı olmalı)

Gerçek cihaza komut gönderir, response doğrular. 22 test. Port iki yöntemle belirtilebilir:

# Yöntem 1: --port argümanı
python -m pytest tests/ -v -k integration --port /dev/tty.usbmodem1101

# Yöntem 2: PORT ortam değişkeni
PORT=/dev/tty.usbmodem1101 python -m pytest tests/ -v -k integration

Dikkat: test_text_* testleri gerçekten yazı yazar. İmleç neredeyse oraya yazılır. Bir metin editörü aç ve imleci oraya bırak.

Hepsini Birlikte

python -m pytest tests/ -v --port /dev/tty.usbmodem1101

İnteraktif Mod

Manuel test ve debug için:

python tests/test_aihid.py /dev/tty.usbmodem1101

8. Pratik Örnekler

Web Sitesine Login

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.click("L")                                          # username alanına tıkla
    hid.text("[email protected]{TAB}{DELAY:300}Sifre123{ENTER}")

Dosya Kopyala-Yapıştır

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.combo("KEY_LEFT_CTRL", "a")    # Tümünü seç
    hid.combo("KEY_LEFT_CTRL", "c")    # Kopyala
    hid.combo("KEY_LEFT_ALT", "KEY_TAB")  # Sonraki pencere
    time.sleep(0.5)
    hid.combo("KEY_LEFT_CTRL", "v")    # Yapıştır

macOS Spotlight ile Uygulama Aç

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.combo("KEY_LEFT_GUI", "KEY_SPACE")   # Spotlight aç
    time.sleep(0.5)
    hid.text("Terminal")
    hid.press("KEY_RETURN")

Shift ile Metin Seçip Silme

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.press("KEY_HOME")                    # Satır başı
    hid.hold("KEY_LEFT_SHIFT")               # Shift basılı
    hid.press("KEY_END")                     # Satır sonu (seçer)
    hid.release("KEY_LEFT_SHIFT")            # Shift bırak
    hid.press("KEY_DELETE")                  # Sil

Cihazı Logitech Olarak Göster

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.set_vid(0x046D)
    hid.set_pid(0xC31C)
    hid.set_manufacturer("Logitech")
    hid.set_product("Logitech Keyboard")
    hid.set_serial("LGT2025")
    hid.reboot()

Hızlı Yazım Profili

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    hid.set_human(True)
    hid.set_typing_delay(10, 35)
    hid.set_punctuation_delay(50, 150)
    hid.text("Bu metin hızlı ama insansı yazılacak.")

Sağlık Kontrolü Script'i

from aihid_client import AIHIDClient

with AIHIDClient("/dev/tty.usbmodem1101") as hid:
    if not hid.ping():
        print("FAIL: ping")
        exit(1)

    info = hid.getinfo()
    heap = int(info.get("HEAP", "0"))
    print(f"FW: {info['FW']}")
    print(f"PROTO: {info['PROTO']}")
    print(f"HEAP: {heap} bytes")
    print(f"UPTIME: {info['UP']}s")

    if heap < 50000:
        print("WARNING: low heap")
    else:
        print("OK")

9. Hata Yönetimi

Python client üç exception fırlatabilir:

from aihid_client import AIHIDError, AIHIDTimeout, AIHIDCRCMismatch

try:
    hid.send("WHEEL:abc")
except AIHIDError as e:
    print(f"Cihaz hata döndü: {e.reason}")
    # e.reason = "invalid_number"
    # e.command = "WHEEL:abc"
    # e.crc = 0xABCD1234

except AIHIDTimeout:
    print("Cihaz yanıt vermedi")

except AIHIDCRCMismatch as e:
    print(f"CRC uyuşmazlığı: beklenen {e.expected:08X}, gelen {e.got:08X}")
    # Veri bozulmuş, komutu tekrar gönder

10. Watchdog

Firmware'de 10 saniyelik watchdog çalışır. Herhangi bir sebepten kod donarsa (sonsuz döngü, USB stack hatası), watchdog cihazı otomatik yeniden başlatır.

Normal kullanımda bir şey yapman gerekmez. Uzun TEXT yazımlarında ve büyük fare hareketlerinde watchdog otomatik beslenir.


11. Sorun Giderme

"Serial port'ta hiçbir şey görmüyorum"

  1. USB CDC On BootDisabled mı? (En sık yapılan hata)
  2. Kartı çıkar, farklı USB portuna tak.
  3. Yeni oluşan portu seç.
  4. Baud rate: 115200.

"Türkçe karakterler yanlış yazılıyor"

  1. hid.set_lang("TR") gönder.
  2. Bilgisayarın klavye düzeni Turkish-Q mi kontrol et.
  3. " ve < yer değişiyorsa: hid.set_kb("ISO") (macOS) veya hid.set_kb("ANSI") (Windows/Linux).

"VID/PID değişmiyor"

  1. USB CDC On BootDisabled olmalı.
  2. SET sonrası hid.reboot() çağırdın mı?
  3. Farklı USB portuna taktın mı? (OS cache)
  4. hid.getinfo() ile kontrol et.

"Cihaz dondu / yanıt vermiyor"

  1. 10 saniye bekle — watchdog otomatik yeniden başlatır.
  2. USB'yi çıkar-tak.
  3. Hâlâ yanıt yoksa: boot moduna girip yeniden flash'la.

"CRC Mismatch hatası alıyorum"

  1. USB kablosu bozuk olabilir — değiştir.
  2. Baud rate doğru mu (115200)?
  3. Başka bir program aynı portu kullanıyor olabilir.

"AIHIDTimeout hatası alıyorum"

  1. Port doğru mu?
  2. Cihaz çalışıyor mu? (LED yanıyor mu?)
  3. Timeout süresini artır: AIHIDClient(port, timeout=10.0)
  4. hid.ping() ile test et.

12. Tuş İsimleri

İsim Tuş
KEY_RETURN / KEY_ENTER Enter
KEY_ESC / KEY_ESCAPE Escape
KEY_BACKSPACE Backspace
KEY_TAB Tab
KEY_SPACE Boşluk
KEY_CAPS_LOCK Caps Lock
KEY_F1KEY_F12 Fonksiyon tuşları
KEY_PRINT_SCREEN Print Screen
KEY_INSERT Insert
KEY_DELETE Delete
KEY_HOME Home
KEY_END End
KEY_PAGE_UP Page Up
KEY_PAGE_DOWN Page Down
KEY_UP / KEY_UP_ARROW Yukarı ok
KEY_DOWN / KEY_DOWN_ARROW Aşağı ok
KEY_LEFT / KEY_LEFT_ARROW Sol ok
KEY_RIGHT / KEY_RIGHT_ARROW Sağ ok
KEY_LEFT_CTRL Sol Ctrl
KEY_LEFT_SHIFT Sol Shift
KEY_LEFT_ALT Sol Alt
KEY_LEFT_GUI Sol Win / Cmd
KEY_RIGHT_CTRL Sağ Ctrl
KEY_RIGHT_SHIFT Sağ Shift
KEY_RIGHT_ALT Sağ Alt (AltGr)
KEY_RIGHT_GUI Sağ Win / Cmd
KEY_NUM_LOCK Num Lock
KEY_SCROLL_LOCK Scroll Lock

13. Validasyon Limitleri

Parametre Min Max Aşılırsa
{DELAY:ms} 0 30000 Clamp edilir
{K:KEY:N} tekrar 1 255 Clamp edilir
MOUSE / DRAG koordinat -10000 10000 Clamp edilir
WHEEL -127 127 Clamp edilir
SET:TYPMIN/TYPMAX 0 5000 Clamp edilir
SET:TYPOMIN/TYPOMAX 0 10000 Clamp edilir
SET:MANU/PROD/SERIAL 1 63 karakter ERR too_long
TEXT: komutu - 4096 byte Kesilir + WARN
Diğer komutlar - 512 byte ERR cmd_too_long

Negatif sayılar: sayısal alanlarda negatif değer 0'a clamp edilir (gecikme, VID/PID). Mouse/wheel'da negatif geçerlidir (yön belirtir).

TEXT filtrelenen byte'lar: \x00 (NUL), \x01 (SOH), \x02 (STX), \x04 (EOT) byte'ları TEXT içeriğinden sessizce temizlenir. Bunlar firmware'in dahili sentinel/CRC ayırıcı byte'larıdır. 4-byte UTF-8 dizileri (emoji, U+10000+) desteklenmez ve atlanır.


14. Teknik Detaylar

  • MCU: ESP32-S2 (Xtensa LX7, 240MHz, 320KB SRAM)
  • USB: Native USB-OTG, TinyUSB stack
  • HID: pressRaw() ile doğrudan HID scancode (kütüphane ASCII bypass)
  • NVS: Preferences kütüphanesi ile kalıcı ayar saklama
  • Watchdog: esp_task_wdt, 10s timeout, panic reboot
  • CRC: esp_rom_crc32_le (IEEE 802.3 CRC32)
  • TR-Q Map: 95 ASCII + 13 Unicode karakter, ISO/ANSI swap
  • Human Typing: esp_random() tabanlı, karakter sınıfına göre değişken gecikme
  • Buffer: Safe serial read, hard byte limit, UTF-8/escape-aware tail trim
  • Heap Guard: 8KB altında komut ERR ile reddedilir (CRC korunur)
  • TEXT Escapes: \n, \t, \\, {ENTER}, {TAB}, {DELAY:ms}, {K:KEY:N}
  • TEXT Chunking: Client 3900 byte'lık parçalara böler (UTF-8/escape aware)
  • Partition: 4MB flash, ffat (1.2MB APP + 1.5MB FATFS), OTA destekli

15. Credits

Bu proje aşağıdaki açık kaynak kütüphaneler ve araçlar üzerine inşa edilmiştir:

Kütüphane / Araç Açıklama Link
ESP32 Arduino Core ESP32 ailesi için Arduino framework github.com/espressif/arduino-esp32
TinyUSB ESP32-S2 native USB-OTG stack github.com/hathach/tinyusb
EspTinyUSB (chegewara) ESP32-S2/S3 USB HID kütüphanesi github.com/chegewara/EspTinyUSB
USBHIDKeyboard / USBHIDMouse Arduino ESP32 USB HID kütüphaneleri ESP32 Arduino Core içinde
Preferences ESP32 NVS (Non-Volatile Storage) sarmalayıcı ESP32 Arduino Core içinde
pyserial Python serial port kütüphanesi github.com/pyserial/pyserial
pytest Python test framework github.com/pytest-dev/pytest
Arduino IDE Geliştirme ortamı ve derleyici arduino.cc
Espressif IDF ESP32 alt seviye SDK (ROM CRC32, WDT) github.com/espressif/esp-idf

Donanım: Wemos/Lolin S2 Mini — ESP32-S2 tabanlı geliştirme kartı.

AI Desteği: Kod geliştirme, güvenlik auditi ve dokümantasyon sürecinde Claude (Anthropic) kullanılmıştır.


16. Lisans

Copyright 2026 Burak Boz

Bu proje Creative Commons Attribution 4.0 International (CC BY 4.0) lisansı ile lisanslanmıştır.

Özgürce kullanabilir, değiştirebilir ve dağıtabilirsiniz — tek koşul kaynak belirtmektir.

Proje: github.com/BurakBoz/esp-ai-hid

About

AI-powered USB HID Controller — ESP32-S2 keyboard/mouse emulator with bidirectional CRC32 protocol, Turkish/US layout, human typing simulation, and Python client.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors