# Water Data Comparison - Lilian Labs vs. InfluxDB

## Übersicht

Das Water Data Comparison System ermöglicht den direkten Vergleich zwischen manuellen Messungen (Lilian Labs) und automatischen Sensordaten (InfluxDB).

## Features

✅ **Daten-Merging** - Intelligente Zusammenführung zeitlich naher Messungen  
✅ **Abweichungs-Analyse** - Automatische Berechnung von Differenzen  
✅ **Interaktive Charts** - Visualisierung mit Chart.js  
✅ **Detailansicht** - Tabellarische Übersicht aller Vergleiche  
✅ **Statistiken** - Automatische Berechnung von Durchschnittswerten  
✅ **Flexible Filter** - Nach Standort und Zeitbereich filterbar  

---

## Komponenten

### 1. InfluxDBService (`src/Service/InfluxDBService.php`)
Generischer Service für InfluxDB-Zugriffe:
- Query-Ausführung
- Measurement-Discovery
- Daten-Extraktion
- Verbindungstest

### 2. WaterDataComparisonService (`src/Service/WaterDataComparisonService.php`)
Kern-Service für Datenvergleiche:
- Lädt Lilian Labs Daten aus MySQL
- Lädt InfluxDB Daten
- Merged Daten zeitlich (5 Minuten Toleranz)
- Berechnet Abweichungen
- Erstellt Statistiken
- Bereitet Chart-Daten vor

### 3. WaterDataComparisonController (`src/Controller/Admin/WaterDataComparisonController.php`)
Admin-Controller:
- `/admin/water-comparison` - Hauptansicht mit Charts
- `/admin/water-comparison/api/compare` - JSON API
- `/admin/water-comparison/details` - Detailtabelle

---

## Verwendung

### Im Admin-Bereich

**Navigation:** Admin → Integration → Daten-Vergleich

**Features:**
1. **Standort wählen** - Filtert nach Messort
2. **Zeitbereich wählen** - 1-30 Tage rückwirkend
3. **Vergleich laden** - Lädt und visualisiert Daten
4. **Detailansicht** - Zeigt alle Messungen tabellarisch

### Charts

**Drei Vergleichs-Charts:**
- 📊 pH-Wert Vergleich
- 📊 Freies Chlor Vergleich
- 📊 Gesamtchlor Vergleich

**Legende:**
- 🔵 **Blau (Lilian Labs):** Manuelle Messungen
- 🟢 **Grün (InfluxDB):** Automatische Sensordaten

---

## Daten-Merging

### Zeitfenster
- **Toleranz:** 5 Minuten (300 Sekunden)
- **Logik:** Sucht für jede Lilian Labs Messung die zeitlich nächste InfluxDB-Messung
- **Match:** Wenn Zeitdifferenz < 5 Minuten

### Abweichungs-Berechnung

**Für jeden Parameter wird berechnet:**
```php
Differenz = Lilian Labs Wert - InfluxDB Wert
Prozentual = (Differenz / InfluxDB Wert) × 100
Toleranz = Ist Differenz innerhalb definierter Grenzen?
```

**Toleranzen:**
- pH: ±0.2
- Freies Chlor: ±0.1 mg/l
- Gesamtchlor: ±0.15 mg/l

---

## Statistiken

**Automatisch berechnet:**
- Gesamtzahl Lilian Labs Messungen
- Anzahl Messungen mit InfluxDB-Match
- Anzahl Messungen ohne InfluxDB-Match
- Durchschnittliche Zeitdifferenz (Sekunden)
- Durchschnittliche Abweichungen pro Parameter
- Min/Max Abweichungen

---

## API-Verwendung

### Compare Endpoint

```javascript
GET /admin/water-comparison/api/compare?location=LOCATION&days=7

Response:
{
  "success": true,
  "data": {
    "lilian_labs": [...],
    "influx": [...],
    "comparison": [...],
    "statistics": {...},
    "timeRange": {...}
  },
  "chartData": {
    "labels": [...],
    "datasets": {...}
  }
}
```

---

## InfluxDB Konfiguration

### Erforderliche ENV-Variablen

```env
INFLUXDB_HOST=localhost
INFLUXDB_PORT=8086
INFLUXDB_DATABASE=water_quality
INFLUXDB_USERNAME=admin
INFLUXDB_PASSWORD=password
```

### Standort-Mapping (Prefix-basiert)

**Problem:** InfluxDB Measurements haben technische Namen (z.B. `bayrol_chlor`, `bayrol_ph`, `narwali2_ph`), während Lilian Labs Standortnamen verwendet (z.B. "Blankenheim", "Köln").

**Lösung:** Prefix-basiertes Mapping in Lilian Labs Config!

**Konfiguration:**
1. Gehe zu: **Admin → Lilian Labs → Konfiguration**
2. Scrolle zu **"InfluxDB Standort-Mapping"**
3. Definiere Mappings im JSON-Format mit **Präfixen**:

```json
{
  "bayrol": "Blankenheim",
  "narwali2": "Köln Mengenicher Strasse",
  "mobi": "Mobiler Sensor"
}
```

**Format:**
- **Key:** InfluxDB Measurement-Präfix (z.B. `bayrol`)
- **Value:** Lilian Labs Standort (z.B. `Blankenheim`)

**Wie Prefix-Matching funktioniert:**
1. Du definierst nur **Präfixe** (z.B. `bayrol`)
2. **ALLE** Measurements die damit beginnen werden automatisch gemappt:
   - `bayrol_chlor` → "Blankenheim"
   - `bayrol_ph` → "Blankenheim"
   - `bayrol_temp` → "Blankenheim"
   - `bayrol_chlor_total` → "Blankenheim"
3. System lädt nur Measurements mit konfigurierten Präfixen
4. Wandelt Measurement-Namen in Standort-Namen um
5. Merged Daten basierend auf Standort-Namen

**Vorteile:**
- ✅ **Einfach:** Nur ein Eintrag pro Standort
- ✅ **Flexibel:** Neue Measurements werden automatisch erkannt
- ✅ **Wartbar:** Keine Änderungen bei neuen Sensoren nötig

**Priorität bei mehreren Matches:**
Längste Präfixe haben Vorrang! Beispiel:
```json
{
  "bayrol": "Standort A",
  "bayrol_special": "Standort B"
}
```
- `bayrol_special_ph` → "Standort B" (längerer Match)
- `bayrol_normal_ph` → "Standort A" (kürzerer Match)

### Measurement-Struktur

**InfluxDB Measurements können haben:**
- **Fields:** `ph`, `chlorine_free`, `chlorine_total`, `cl_free`, `cl_total`, `temperature`, `temp`
- **Timestamp:** ISO 8601 Format

**Das System unterstützt verschiedene Field-Namen:**
- `ph` oder `pH`
- `chlorine_free`, `cl_free`, `chlor_free`
- `chlorine_total`, `cl_total`, `chlor_total`
- `temperature`, `temp`

**Beispiel-Query:**
```sql
SELECT * FROM "bayrol_chlor" 
WHERE time >= '2025-11-20T00:00:00Z' 
  AND time <= '2025-11-27T00:00:00Z'
ORDER BY time ASC
```

---

## Anpassungen

### Measurement-Namen konfigurieren

**Empfohlene Methode:** Nutze das Prefix-Mapping in der Config!

1. **Admin → Lilian Labs → Konfiguration**
2. **InfluxDB Standort-Mapping** bearbeiten
3. Füge deine Präfixe hinzu:

```json
{
  "dein_prefix": "Dein Standort",
  "anderer_prefix": "Anderer Standort"
}
```

**Beispiel:** Wenn deine Measurements `sensor1_ph`, `sensor1_chlor`, `sensor2_ph` heißen:
```json
{
  "sensor1": "Schwimmbad Nord",
  "sensor2": "Schwimmbad Süd"
}
```

### Fallback: Code anpassen

Falls du automatische Discovery nutzen willst:

**In `InfluxDBService::getWaterMeasurements()`:**
```php
// Passe die Filter an:
$waterMeasurements = array_filter($measurements, function($m) {
    return stripos($m, 'dein_measurement_name') !== false 
        || stripos($m, 'anderer_name') !== false;
});
```

### Field-Namen anpassen

**In `WaterDataComparisonService::getInfluxData()`:**
```php
$dataPoint = [
    // Passe Field-Namen an:
    'ph' => isset($record['dein_ph_field']) ? (float)$record['dein_ph_field'] : null,
    'chlorine_free' => isset($record['dein_cl_field']) ? (float)$record['dein_cl_field'] : null,
    // ...
];
```

### Toleranzen anpassen

**In `WaterDataComparisonService::isWithinTolerance()`:**
```php
$tolerances = [
    'ph' => 0.3,              // Ändere auf deine Werte
    'chlorine_free' => 0.15,  // Ändere auf deine Werte
    // ...
];
```

---

## Troubleshooting

### Keine InfluxDB-Daten

1. **Verbindung prüfen:**
   ```bash
   curl "http://localhost:8086/query?q=SHOW+DATABASES"
   ```

2. **ENV-Variablen prüfen:**
   ```bash
   php bin/console debug:container --env-vars
   ```

3. **Measurements prüfen:**
   ```bash
   curl "http://localhost:8086/query?db=DATABASE&q=SHOW+MEASUREMENTS"
   ```

### Keine Matches gefunden

- **Zeitfenster zu eng?** Erhöhe `$timeWindow` in `WaterDataComparisonService::mergeAndCompare()`
- **Unterschiedliche Standorte?** Prüfe Location-Namen in beiden Systemen
- **Zeitzone-Probleme?** Stelle sicher, dass beide Systeme UTC verwenden

### Charts zeigen keine Daten

1. **Browser-Console prüfen** (F12)
2. **API-Response prüfen:** `/admin/water-comparison/api/compare`
3. **JavaScript-Fehler?** Chart.js korrekt geladen?

---

## Performance

### Optimierungen

**Für große Datenmengen:**

1. **Zeitbereich limitieren:**
   - Standard: 7 Tage
   - Maximum empfohlen: 30 Tage

2. **Standort filtern:**
   - Immer einen spezifischen Standort wählen
   - Reduziert Datenmenge erheblich

3. **Caching aktivieren:**
   ```php
   // In WaterDataComparisonService
   // TODO: Redis/Memcached für Comparison-Results
   ```

---

## Erweiterungsmöglichkeiten

### Geplante Features

- 📧 **E-Mail-Alerts** bei großen Abweichungen
- 📊 **Trend-Analysen** über längere Zeiträume
- 🤖 **ML-basierte Anomalie-Erkennung**
- 📈 **Export-Funktionen** (CSV, PDF)
- 🔔 **Echtzeit-Benachrichtigungen**
- 📱 **Mobile-optimierte Ansicht**
- 🎯 **Kalibrierungs-Empfehlungen**

### Integration-Möglichkeiten

- **Grafana Dashboard:** Für Echtzeit-Monitoring
- **Alerting System:** Bei kritischen Abweichungen
- **Report-Generator:** Automatische wöchentliche Reports
- **Kalibrierungs-Tracking:** Sensor-Wartung dokumentieren

---

## Best Practices

### Mess-Intervalle

**Empfohlen:**
- **Lilian Labs (manuell):** 2-3x täglich
- **InfluxDB (automatisch):** Alle 5-15 Minuten
- **Vergleich durchführen:** Täglich oder wöchentlich

### Toleranzen definieren

**Basis:**
- Schwimmbad-Normen (DIN 19643)
- Hersteller-Spezifikationen der Sensoren
- Erfahrungswerte aus Betrieb

### Kalibrierung

- Sensoren regelmäßig kalibrieren
- Kalibrierung bei großen Abweichungen
- Kalibrierungs-Historie dokumentieren

---

## Support

**Bei Fragen oder Problemen:**
1. Logs prüfen: `var/log/prod.log`
2. InfluxDB-Verbindung testen
3. API-Response analysieren
4. Measurement-Namen verifizieren

---

## Changelog

### Version 1.1.0 (26.11.2025)
- ✅ **InfluxDB Standort-Mapping** - Konfigurierbare Zuordnung von Measurements zu Standorten
- ✅ **Mapping-Editor** - UI für einfache Konfiguration
- ✅ **Automatisches Filtering** - Nur gemappte Measurements werden geladen
- ✅ **Flexible Field-Namen** - Unterstützt verschiedene Schreibweisen (chlorine_free, cl_free, etc.)

### Version 1.0.0 (26.11.2025)
- ✅ Initiales Release
- ✅ Lilian Labs + InfluxDB Integration
- ✅ Interaktive Charts
- ✅ Detailansicht mit Tabelle
- ✅ Statistik-Berechnungen
- ✅ Flexible Filter
- ✅ API-Endpoint

