diff --git a/README.md b/README.md
index 4c5de6e..aa10156 100644
--- a/README.md
+++ b/README.md
@@ -57,12 +57,14 @@ Die Anwendung unterstützt folgende JSON-Formate:
{
"Uhrzeit": "10:00:38",
"SDS_P1": 9.15,
- "SDS_P2": 6.22
+ "SDS_P2": 6.22,
+ "sensor_name": "Sensor-1"
},
{
"Uhrzeit": "10:15:36",
"SDS_P1": 9.75,
- "SDS_P2": 5.97
+ "SDS_P2": 5.97,
+ "sensor_name": "Sensor-1"
}
]
```
@@ -72,7 +74,7 @@ Oder als Objekt mit Daten-Array:
```json
{
"data": [
- { "Uhrzeit": "10:00:38", "SDS_P1": 9.15, "SDS_P2": 6.22 }
+ { "Uhrzeit": "10:00:38", "SDS_P1": 9.15, "SDS_P2": 6.22, "sensor_name": "Sensor-1" }
]
}
```
@@ -94,6 +96,7 @@ Für die automatische Datenerfassung und -speicherung muss eine NocoDB-Datenbank
| `Title` | Text | Optionaler Titel (kann leer bleiben) |
| `SDS_P1` | Number | Feinstaub PM10-Wert |
| `SDS_P2` | Number | Feinstaub PM2.5-Wert |
+| `sensor_name` | Text | Bezeichnung des Sensors zur Unterscheidung mehrerer Sensoren |
| `BME280_Temperature` | Number | Temperatur in °C |
| `BME280_Humidity` | Number | Luftfeuchtigkeit in % |
| `BME280_Pressure` | Number | Luftdruck (optional) |
@@ -132,7 +135,7 @@ Das Projekt enthält zwei n8n-Workflows für die Automatisierung:
**Workflow-Schritte**:
1. **Webhook**: Empfängt Anfragen auf `/sds-data`
-2. **NocoDB GetAll**: Liest alle Daten aus der Tabelle (SDS_P1, SDS_P2, Uhrzeit)
+2. **NocoDB GetAll**: Liest alle Daten aus der Tabelle (SDS_P1, SDS_P2, Uhrzeit, sensor_name)
3. **JavaScript Code**: Filtert die letzten 50 Einträge
4. **Response**: Gibt JSON-Daten zurück
diff --git a/feinstaub-webhook.json b/feinstaub-webhook.json
index ce2a58f..6e0fc11 100644
--- a/feinstaub-webhook.json
+++ b/feinstaub-webhook.json
@@ -23,7 +23,8 @@
"fields": [
"SDS_P1",
"SDS_P2",
- "Uhrzeit"
+ "Uhrzeit",
+ "sensor_name"
]
}
},
@@ -130,7 +131,7 @@
"availableInMCP": false,
"errorWorkflow": "0bBZzSE6SUzVsif5"
},
- "versionId": "9ece3377-504a-4df7-900d-ef23c1bd5905",
+ "versionId": "220f6cf9-fc5b-4afe-875d-a70cb8cadf36",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "2f7fd37175cefa82de44e06b8af9ab9c01e7956018045d6efc4f7bf1588a41eb"
diff --git a/feinstaub.html b/feinstaub.html
index d31138d..a532c13 100644
--- a/feinstaub.html
+++ b/feinstaub.html
@@ -182,6 +182,28 @@
border-radius: 5px;
font-size: 14px;
}
+ .sensor-selection {
+ width: 100%;
+ margin-top: 20px;
+ padding: 20px;
+ background: #f7fafc;
+ border-radius: 5px;
+ border-left: 4px solid #48bb78;
+ display: none;
+ }
+ .sensor-selection h3 {
+ margin-bottom: 10px;
+ color: #2d3748;
+ }
+ .sensor-selection select {
+ width: 100%;
+ padding: 10px 15px;
+ border: 2px solid #e2e8f0;
+ border-radius: 5px;
+ font-size: 14px;
+ background: white;
+ cursor: pointer;
+ }
@@ -221,7 +243,14 @@
-
+
+
+
Sensor-Auswahl
+
+
+
@@ -254,9 +283,45 @@
let filterSettings = {
enabled: true,
p1Max: 100,
- p2Max: 100
+ p2Max: 100,
+ selectedSensor: 'all'
};
+ function detectAndPopulateSensors(data) {
+ // Prüfen, ob sensor_name Feld vorhanden ist
+ const hasSensorName = data.length > 0 && data.some(item => item.sensor_name);
+
+ if (!hasSensorName) {
+ // Sensor-Auswahl ausblenden, wenn kein sensor_name vorhanden
+ document.getElementById('sensorSelection').style.display = 'none';
+ filterSettings.selectedSensor = 'all';
+ return;
+ }
+
+ // Unique Sensoren extrahieren
+ const sensors = [...new Set(data.map(item => item.sensor_name).filter(Boolean))];
+
+ if (sensors.length > 1) {
+ // Sensor-Auswahl nur anzeigen, wenn mehrere Sensoren vorhanden sind
+ document.getElementById('sensorSelection').style.display = 'block';
+
+ // Dropdown befüllen
+ const select = document.getElementById('sensorSelect');
+ select.innerHTML = '';
+
+ sensors.forEach(sensor => {
+ const option = document.createElement('option');
+ option.value = sensor;
+ option.textContent = sensor;
+ select.appendChild(option);
+ });
+ } else {
+ // Nur ein Sensor vorhanden, Auswahl nicht nötig
+ document.getElementById('sensorSelection').style.display = 'none';
+ filterSettings.selectedSensor = sensors[0] || 'all';
+ }
+ }
+
function calculateOutlierThreshold(values) {
const sorted = [...values].sort((a, b) => a - b);
const q1Index = Math.floor(sorted.length * 0.25);
@@ -269,20 +334,27 @@
}
function applyFilters(data) {
- if (!filterSettings.enabled) {
- document.getElementById('filteredCount').textContent = '0 Datenpunkte entfernt';
- return data;
+ let filtered = data;
+
+ // Filter nach Sensor
+ if (filterSettings.selectedSensor !== 'all') {
+ filtered = filtered.filter(item => item.sensor_name === filterSettings.selectedSensor);
}
- const filtered = data.filter(item => {
- const p1 = parseFloat(item.SDS_P1) || 0;
- const p2 = parseFloat(item.SDS_P2) || 0;
- return p1 <= filterSettings.p1Max && p2 <= filterSettings.p2Max;
- });
+ // Filter nach Ausreißern (nur wenn aktiviert)
+ if (filterSettings.enabled) {
+ const beforeOutlierFilter = filtered.length;
+ filtered = filtered.filter(item => {
+ const p1 = parseFloat(item.SDS_P1) || 0;
+ const p2 = parseFloat(item.SDS_P2) || 0;
+ return p1 <= filterSettings.p1Max && p2 <= filterSettings.p2Max;
+ });
+ const removed = beforeOutlierFilter - filtered.length;
+ document.getElementById('filteredCount').textContent = `${removed} Datenpunkte entfernt`;
+ } else {
+ document.getElementById('filteredCount').textContent = '0 Datenpunkte entfernt';
+ }
- const removed = data.length - filtered.length;
- document.getElementById('filteredCount').textContent = `${removed} Datenpunkte entfernt`;
-
return filtered;
}
@@ -334,13 +406,14 @@
function processData(jsonData) {
let data = Array.isArray(jsonData) ? jsonData : (jsonData.data || jsonData.records || []);
-
+
if (data.length === 0) {
showStatus('Keine Daten gefunden. Überprüfen Sie das JSON-Format.', 'error');
return;
}
rawData = data;
+ detectAndPopulateSensors(rawData);
autoDetectThresholds(rawData);
renderChart();
}
@@ -525,14 +598,20 @@
renderChart();
});
+ // Sensor-Auswahl Event Listener
+ document.getElementById('sensorSelect').addEventListener('change', function(e) {
+ filterSettings.selectedSensor = e.target.value;
+ renderChart();
+ });
+
// Beispieldaten für Demo
const exampleData = [
- { Uhrzeit: '09:45:36', SDS_P1: 17.53, SDS_P2: 96272.72 },
- { Uhrzeit: '10:00:38', SDS_P1: 9.15, SDS_P2: 6.22 },
- { Uhrzeit: '10:15:36', SDS_P1: 9.75, SDS_P2: 5.97 },
- { Uhrzeit: '10:30:36', SDS_P1: 9.93, SDS_P2: 6.35 },
- { Uhrzeit: '10:45:36', SDS_P1: 9.55, SDS_P2: 5.88 },
- { Uhrzeit: '11:00:36', SDS_P1: 12.15, SDS_P2: 6.93 }
+ { Uhrzeit: '09:45:36', SDS_P1: 17.53, SDS_P2: 96272.72, sensor_name: 'Sensor-1' },
+ { Uhrzeit: '10:00:38', SDS_P1: 9.15, SDS_P2: 6.22, sensor_name: 'Sensor-1' },
+ { Uhrzeit: '10:15:36', SDS_P1: 9.75, SDS_P2: 5.97, sensor_name: 'Sensor-2' },
+ { Uhrzeit: '10:30:36', SDS_P1: 9.93, SDS_P2: 6.35, sensor_name: 'Sensor-1' },
+ { Uhrzeit: '10:45:36', SDS_P1: 9.55, SDS_P2: 5.88, sensor_name: 'Sensor-2' },
+ { Uhrzeit: '11:00:36', SDS_P1: 12.15, SDS_P2: 6.93, sensor_name: 'Sensor-2' }
];
// Demo-Daten initial laden