# Meter Entity

Reprezentarea unui contor Bluetooth conectat (UM25C, UM34C, TC66C).

## Responsabilități

- Modelarea unui dispozitiv USB power meter BT
- Gestionarea stării de conectare şi comunicare
- Citirea măsurătorilor de la dispozitiv
- Persistență metadate conector (device, timestamp, expiry)

## Invarianți

- **MUST**: Un Meter are un `id` (UUID) unic în aplicaţie
- **MUST**: Un Meter cu `macAddress` nu poate fi duplicat în Core Data (Cloud-Kit safe)
- **MUST**: Starea `OperationalState` este monoton crescătoare: `notPresent → ... → dataIsAvailable`
- **MUST**: Dacă `OperationalState` este `peripheralConnected` sau mai mare, trebuie să existe o conexiune BT activă
- **SHOULD**: Un Meter inactiv (fără măsurători > 2 ore) ar trebui să se reconecteze automat
- **MAY**: Temperature unit preference (Celsius/Fahrenheit) poate fi schimbat oricând

## Estados operaţionale

```
notPresent
  ↓
peripheralNotConnected
  ↓
peripheralConnectionPending
  ↓
peripheralConnected
  ↓
peripheralReady
  ↓
comunicating ↔ dataIsAvailable
```

## API Public

### Proprietăţi

| Proprietate | Tip | Descriere | Observaţii |
|---|---|---|---|
| `id` | UUID | Identificator unic | Generat la creare |
| `macAddress` | String | Adresa MAC BT | De ex: "AA:BB:CC:DD:EE:FF" |
| `meter` | Model | Tipul: UM25C, UM34C, TC66C | Immutable după creare |
| `meterName` | String | Nume ales de utilizator | Persistent în Core Data |
| `operationalState` | OperationalState | Starea curentă | Published, triggers UI updates |
| `lastDataPoint` | Measurement? | Ultima măsurătoare | Nullable |
| `connectionMetadata` | ConnectionMetadata? | Info conexiune curentă | Device, timestamp, expiry |
| `discoveryMetadata` | DiscoveryMetadata? | Info descoperire BT | Last seen, seen by |
| `temperatureUnit` | TemperatureUnitPreference | Unitatei temperatură | Celsius/Fahrenheit |

### Metode

```swift
// Conectare
func connect() 
// MUST: tranzițe starea la peripheralConnectionPending
// SHOULD: se conectează în max 5s

func disconnect()
// MUST: tranzițe starea la peripheralNotConnected
// MUST: eliberează resurse BT

// Citire măsurători
func requestMeasurement() -> Bool
// SHOULD: retur true dacă cererea a fost trimisă
// SHOULD: se așteaptă răspuns în max 3s (timeout)
// MUST: nu trimite dacă starea este < comunicating

func processMeasurementData(_ data: Data) -> Measurement?
// Parsează payload-ul de la dispozitiv
// MUST: retur nil dacă payload-ul e invalid
// SHOULD: loghează checksum errors

// Gestionare sesiuni
func startChargeRecord(for device: ChargedDevice) -> ChargeRecord
// Inițiază o nouă sesiune de încărcare

func endChargeRecord(_ record: ChargeRecord)
// Finalizează sesiunea

// Naming
func renameToMeter(_ newName: String)
// MUST: actualizează proprietatea şi persistă în Core Data
```

## Comportamente critice

### Reconexiune automată

- **MUST**: Dacă `OperationalState < peripheralConnected`, retry-ează conectarea
- **SHOULD**: Backoff exponential: 1s, 2s, 4s, 8s, max 60s
- **SHOULD**: Anulează retry-urile dacă utilizatorul deconectează manual

### Timeout pe măsurători

- **MUST**: Dacă nu primim răspuns în 3s după cerere, timeout-ul măsurătorii
- **SHOULD**: Loghează timeout-urile pentru debugging
- **MAY**: Incrementează contorul de failed requests

### Stare după disconnecţie accidentală

- **MUST**: Dacă BT drop-ă accidental, starea revine la `peripheralNotConnected`
- **SHOULD**: Încearcă reconexiune automată (backoff)
- **MAY**: Notifică UI-ul cu banner "Meter disconnected"

### Validare MAC address

- **MUST**: MAC address trebuie să fie format valid (XX:XX:XX:XX:XX:XX)
- **MUST**: Dacă MAC e invalid, Meter nu poate fi creat

## Testare

### Unit tests

```swift
// Stări operaţionale
test_operationalStateTransition()
test_stateMonotonicity()

// Conectare
test_connectInitiatesPeripheralConnectionPending()
test_disconnectCleansUpResources()
test_reconnectWithBackoff()

// Măsurători
test_requestMeasurementFailsIfStateInvalid()
test_processMeasurementDataWithValidPayload()
test_measurementTimeout()

// Naming
test_renameUpdatesPersistence()
```

### Integration tests

- [ ] Meter apare în Sidebar după scan
- [ ] Meter se reconectează după BT drop
- [ ] Măsurătorile se salvează pentru ChargedDevice
- [ ] Temperature unit e persistent între app restarts

## Dependenţe

- `BluetoothManager`: gestionează Core Bluetooth
- `ChargeInsightsStore`: salvează măsurătorile
- `AppData`: CloudKit sync

## Note

- Legat: [CloudKit Sync](./CloudKitSync.md) (persistență MAC, name)
- Legat: [Bluetooth Discovery](./BluetoothDiscovery.md) (scan, advertisement)
