Operaţii principale care orchestrează aplicaţia.
AppData este singleton-ul global care orchestrează toate subsistemele.
let appData = AppData()
AppDelegate.application(_:didFinishLaunchingWithOptions:)SceneDelegate.scene(_:willConnectTo:options:)NSPersistentCloudKitContainer cu name "CKModel"CloudDeviceSettingsStore (wraps NSManagedObjectContext)AppDelegate.application(_:didFinishLaunchingWithOptions:):
AppData()cloudStoreRebuildVersionSceneDelegate.scene(_:willConnectTo:options:):
appData.activateCloudDeviceSync(context: sceneContext)saveIfNeeded())notPresent
↓
peripheralNotConnected ← (user disconnect)
↓
peripheralConnectionPending
↓
peripheralConnected
↓
peripheralReady
↓
comunicating ↔ dataIsAvailable
// Conectare inițială
blutooth.connect(to peripheralUUID: UUID, type: Model)
// MUST: inițiază CBCentralManager scan
// MUST: se conectează la UUID specific
// SHOULD: timeout = 5s
// MUST: pe succes, tranzițe la peripheralConnected
// Deconectare
bluetooth.disconnect(from meter: Meter)
// MUST: anulează reconnect logic
// MUST: eliberează resurse
// MUST: marchez ca manual disconnect
// Auto-reconnect
bluetooth.autoReconnect(meter: Meter, backoff: Backoff)
// SHOULD: exponential backoff: 1s, 2s, 4s, 8s, max 60s
// MUST: anulează dacă utilizator disconnect manual
// MUST: max 3 retry-uri consecutive
let session = meter.startChargeRecord(for: device)
ChargeRecord(sessionID: UUID(), startTime: now())swift
let measurement = meter.lastDataPoint
session.addMeasurement(measurement)
swift
meter.endChargeRecord(session)
totalEnergy = ∑(V * A * Δt)completedstartTime <= now() <= (endTime || ∞)cloudStoreRebuildVersion (curent: 3)Upload: Locale changes → Core Data → CloudKit
swift
cloudStore.upsertDeviceSettings(
macAddress: "AA:BB:CC:DD:EE:FF",
meterName: "Kitchen Meter",
tc66TemperatureUnit: .celsius,
connectionMetadata: ...
)
Download: CloudKit changes → Core Data → UI
Conflict resolution: Dacă două modificări simultane
// CloudDeviceSettingsStore.swift
func upsertDeviceSettings(
macAddress: String,
meterName: String,
tc66TemperatureUnit: TemperatureUnitPreference?,
connectionMetadata: ConnectionMetadata?,
discoveryMetadata: DiscoveryMetadata?
)
NSUbiquitousKeyValueStore sincronizează:
- MeterNames: {macAddress → meterName}
- TC66TemperatureUnits: {macAddress → unit}
Error: BT peripheral not found
→ Retry connect cu backoff
→ Max 3 retries, apoi fallback offline mode
Error: Characteristic not found
→ Log error
→ Mark meter incompatible (UI warning)
Error: Read timeout
→ Retry measurement request
→ Increment timeout counter
Error: Network unavailable
→ Queue pending changes
→ Retry la next network change
Error: Conflict detected
→ Merge data (last write wins)
→ Retry sync
Error: Quota exceeded
→ Log error
→ Notify user (prune old data?)
test_appDataInitializes_CoreDataAndCloudKit()
test_bluetoothConnectInitiatesProperStateTransition()
test_bluetoothDisconnect_CleansUp()
test_autoReconnectBackoff_ExponentialScaling()
test_sessionStartCreatesValidRecord()
test_sessionEndCalculatesEnergy()
test_cloudSyncUpsert_SavesToCoreData()
test_discoveryThrottling_RespectsTiming()
test_conflictResolution_LastWriteWins()
AppData: orchestrează totBluetoothManager: gestionează Core BluetoothCloudDeviceSettingsStore: Core Data + CloudKitChargeInsightsStore: sesiuni persistenteConsumptionMonitorStore: monitorizare consum