ESP-Point kendi yan projem: ESP32 tabanlı küçük bir IoT cihazı ve iOS uygulaması, hâlâ geliştirme aşamasında. Aşağıdakiler ölçülmüş ürün sonuçları değil; mimari tasarım kararları ve tasarım hedefleri.
Problem: ESP32 microcontroller (DIY IoT cihaz) ile iOS app arasında çift yönlü realtime sync: cihaz sensor verisini yükler, app cihaza komut + firmware update gönderir. Offline-first zorunlu — cihaz internetsiz lokasyonlarda kullanılacak.
Tasarım hedefleri: 50ms BLE handshake median, 3 günlük offline dayanım (local cache + delayed sync), OTA firmware update için %99 üstü başarı oranı. Üçü de hedef — ölçülmüş sonuç değil.
1. Architecture
1[ESP32 Device]2 ↓ BLE (peripheral)3[iOS App — central]4 ↓ Wi-Fi when available5[Firebase Realtime DB + Cloud Storage]6 ↓ sync queue7[Web Dashboard for fleet ops]iOS app proxy / router rolünde: BLE \<-\> Cloud bridge.
2. BLE State Machine: Gerçek Konu
BLE'nin tek "easy demo"su olmaz. State machine fragmentation real production konu:
States:
unpairedScanningpairingpaired(connected)paired-disconnected(cached)firmwareUpdatingerror(her state'ten geçer)
Her transition için iOS CBCentralManager callback'lerinde 2-3 race condition çözmek gerekiyor:
didDisconnect+didFailToConnectoverlap — UUID-based dedupscanForPeripheralsbackground restoration —CBCentralManagerOptionRestoreIdentifierKeyset- Bluetooth state
.poweredOff→.poweredOntransition'da scan otomatik resume etmiyor — explicitscanForPeripheralsre-call
Hedef: 50ms handshake median, connection drop rate %1 altı (endüstri standardı %4-6).
3. Offline Storage: Realm + Sync Queue
3-day offline target. Her sensor reading (saat başı) device storage'a yazılır, sonra sync queue Realm'e push edilir:
1class SyncQueue: Object {2 @Persisted(primaryKey: true) var id: ObjectId3 @Persisted var payload: Data4 @Persisted var createdAt: Date5 @Persisted var retryCount: Int = 06 @Persisted var lastError: String?7}Sync worker:
1final class SyncWorker {2 func runOnce() async {3 let realm = try await Realm()4 let pending = realm.objects(SyncQueue.self)5 .where { $0.retryCount < 5 }6 .sorted(by: \.createdAt)7 .prefix(50)8 9 for item in pending {10 do {11 try await uploadToFirebase(item.payload)12 try realm.write { realm.delete(item) }13 } catch {14 try realm.write {15 item.retryCount += 116 item.lastError = error.localizedDescription17 }18 }19 }20 }21}Network reachability NWPathMonitor ile sync worker tetiklenir. App background'da BGAppRefreshTask ile day-1 retry.
4. OTA Firmware Update
8-12MB binary blob transfer over BLE:
- Bluetooth chunk size: 244 bytes (BLE 5 max safe)
- Sequence number + CRC32 her chunk
- Acknowledgment per 10 chunk batch
- Total transfer: 4-6 dakika (10MB firmware için)
- Resume on disconnect support
Hedef success rate: %99 üstü. Bu bütçeyi tüketen failure mode'lar:
- connection drop son chunk öncesi (en sık vaka)
- device flash corrupt (re-upload ile kurtarılır)
- kritik anda power loss (manuel recovery gerekir)
OTA UI önemli — progress bar + "do not close app" warning + battery indicator. Bu üçü olmadan OTA ekranı doğrudan negatif App Store yorumu üretir.
5. Test Strategy
- Unit tests: Sync queue state machine, BLE manager state transitions (mocked CBCentralManager)
- Integration tests: Realm migration, sync conflict resolution
- Device farm planı: 6 fiziksel ESP32 + 4 iPhone (iOS 16-18) — CI pipeline'da physical test
- Snapshot tests: UI state for each BLE state
Coverage hedefi: Domain layer %90+, BLE manager %75+, UI %65 bandı.
6. iOS App Architecture
- SwiftUI iOS 16+
- BLEManager:
@MainActoractor (Bluetooth callbacks main thread) - DataLayer: Realm primary + Firebase secondary (offline-first)
- Sync orchestrator: BG task + foreground refresh
Memory bütçesi: baseline 105MB, OTA sırasında peak 220MB (firmware buffer).
7. Öğrenimler
1. BLE physical testing zorunlu. Simulator BLE'yi simüle edemez; CI'da fiziksel cihaz şart.
2. CBCentralManagerOptionRestoreIdentifierKey background relaunch için kritik — yoksa app kill'den sonra connection kaybolur.
3. State machine documentation. 6 state'li bir makinede production debug'ı için her transition log'lanmalı.
4. Realm migration schema değişikliklerinde sync queue'yu boşaltabilir — migration testi yazılmazsa bu, kullanıcı tarafında sessiz veri kaybına dönüşür.
5. OTA "abort" button'ı kullanıcıya verme — corrupt flash riski. Sadece pause/resume.
6. Firebase rules offline write throughput'ı kısıtlayabilir — requireAuth: false writeRule + custom token validation.
7. Battery profiling şart: sürekli BLE scan telefonu 8 saat bandına düşürür. Connection-on-demand pattern bu kalemde ~%35 tasarruf verir.
Sonuç: IoT + iOS sync, "happy path" demolarının gösterdiğinden kat kat zor. State machine + offline storage + OTA, baştan planlanmazsa aylarla ölçülen teknik borç demek.
Etiketler
iOS Geliştirme Haberleri
Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.
Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik
