Teil 3: Sensordaten lokal speichern und verwalten
In den ersten beiden Teilen dieser Serie hast du die Shelly-Plattform kennengelernt und erste Skripte erstellt. Jetzt wird es richtig spannend: Du lernst, wie du alle Sensordaten dauerhaft in einer eigenen MySQL-Datenbank speicherst – vollständig lokal, ohne Cloud, mit voller Kontrolle.
Nach diesem Artikel kannst du Temperatur, Luftfeuchtigkeit, Leistungsdaten und Schaltereignisse automatisch in einer Datenbank sammeln. Das ist die Grundlage für spätere Visualisierungen, Auswertungen und Langzeit-Analysen.
1. Warum eine eigene Datenbank?
Die Shelly-Cloud bietet zwar Diagramme und Verlaufsdaten – aber warum solltest du trotzdem eine eigene Datenbank betreiben?
Vorteile der lokalen Datenspeicherung
- Datenschutz: Alle Daten bleiben bei dir – kein Upload in fremde Clouds
- Unabhängigkeit: Keine Abhängigkeit von Internet oder Cloud-Diensten
- Unbegrenzte Speicherung: Keine Limits bei Datenmenge oder Zeitraum
- Flexible Auswertungen: Beliebige SQL-Abfragen für individuelle Analysen
- Integration: Kombiniere Shelly-Daten mit anderen Datenquellen
- Geschwindigkeit: Lokale Abfragen sind deutlich schneller als Cloud-APIs
🎯 Ziel dieses Artikels: Am Ende hast du ein laufendes System, das alle Shelly-Daten automatisch in deine MySQL-Datenbank schreibt – bereit für Visualisierung und Auswertung.
2. Das Gesamtsystem im Überblick
Bevor wir in die Details gehen, hier die Architektur unseres Systems:
[Shelly-Geräte]
↓ JavaScript-Skript
↓ HTTP POST (JSON)
[PHP-Empfangsscript] - dein Server (Raspberry, Mini-PC, Server im Web u.v.m.)
↓ Daten validieren
↓ INSERT Statement
[MySQL-Datenbank] - - dein Server (Raspberry, Mini-PC, Server im Web u.v.m.)
↓ Gespeicherte Daten
[Auswertung & Dashboard]
2.1 Welche Daten speichern wir?
In meinem Bungalow-Setup sammle ich folgende Daten:
- Temperatur und Luftfeuchtigkeit (Shelly H&T WiFi und H&T BLU)
- Leistungsmessung (Shelly Plug S Gen3/4: Watt, Spannung, Energie)
- Schaltzustände (Relais Ein/Aus)
- Geräteinformationen (Geräte-ID, Name, Batteriestatus)
📋 Wichtig zu wissen: JavaScript-Scripting funktioniert nur auf Shelly Plus- und Gen3/4-Geräten (Plug S Gen3/4, BLU Gateway). Der Shelly H&T WiFi unterstützt kein Scripting – hier nutzen wir URL-Aktionen. Der H&T BLU sendet nur Bluetooth-Pakete, die vom Gateway ausgewertet werden.
3. MySQL-Datenbank einrichten
Ich gehe davon aus, dass du bereits einen MySQL/MariaDB-Server laufen hast (z.B. im Proxmox-Container, Raspberry oder einen PC, auf dem Datenbankdienste verfügbar sind).
Bitte schaue dir dazu auch meine Beiträge zur Installation von Apache2 und MySQL an. Dort ist bereits beschrieben, wie du eine Datenbank anlegst und wie die Daten zum Beispiel von einem ESP32 gespeichert werden.
https://diytechadventures.de/sensordaten-an-pc-senden/
https://diytechadventures.de/daten-an-webserver-senden/
Nachfolgende Installation betrifft Debian mit in Proxmox laufenden Datenbank-Container.
Falls noch nicht, installiere MariaDB:
sudo apt install mariadb-server -y
3.1 Datenbank und Benutzer erstellen
Verbinde dich mit deinem MySQL-Server:
mysql -u root -p, oder falls DB und mysql woanders liegt
mysql -h 192.168.2.xxx -u dein User -p
Führe folgende SQL-Befehle aus:
— Datenbank erstellen
CREATE DATABASE shelly_data CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
— Benutzer erstellen
CREATE USER ’shelly_user’@’%‘ IDENTIFIED BY ‚dein_sicheres_passwort‘;
— Rechte vergeben
GRANT ALL PRIVILEGES ON shelly_data.* TO ’shelly_user’@’%‘;
FLUSH PRIVILEGES;
⚠️ Sicherheit: Ersetze ‚dein_sicheres_passwort‘ mit einem starken Passwort! Das ‚%‘ erlaubt Zugriff von allen IPs – für Produktion solltest du das auf spezifische IPs einschränken.
3.2 Tabellen anlegen
Jetzt erstellen wir die Tabellen für unsere verschiedenen Datentypen:
3.2.1 Tabelle für Temperatur und Luftfeuchtigkeit
USE shelly_data; // diese Datenbank unter mysql nutzen
CREATE TABLE sensor_data (
id INT AUTO_INCREMENT PRIMARY KEY,
device_id VARCHAR(50) NOT NULL,
device_name VARCHAR(100),
temperature DECIMAL(5,2),
humidity DECIMAL(5,2),
battery INT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_device_time (device_id, timestamp),
INDEX idx_timestamp (timestamp)
) ENGINE=InnoDB;
3.2.2 Tabelle für Energiemessung
CREATE TABLE power_data (
id INT AUTO_INCREMENT PRIMARY KEY,
device_id VARCHAR(50) NOT NULL,
device_name VARCHAR(100),
power DECIMAL(8,2),
voltage DECIMAL(6,2),
current DECIMAL(6,2),
energy_total DECIMAL(10,3),
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_device_time (device_id, timestamp),
INDEX idx_timestamp (timestamp)
) ENGINE=InnoDB;
3.2.3 Tabelle für Schaltereignisse
CREATE TABLE switch_events (
id INT AUTO_INCREMENT PRIMARY KEY,
device_id VARCHAR(50) NOT NULL,
device_name VARCHAR(100),
switch_state BOOLEAN,
event_type VARCHAR(20),
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_device_time (device_id, timestamp),
INDEX idx_timestamp (timestamp)
) ENGINE=InnoDB;
💡 Indizes: Die INDEX-Anweisungen beschleunigen spätere Abfragen erheblich. Der kombinierte Index idx_device_time ist besonders wichtig für Zeitraumabfragen pro Gerät.
3.3 Tabellen prüfen
Prüfe ob alle Tabellen korrekt angelegt wurden:
SHOW TABLES;
DESCRIBE sensor_data;
DESCRIBE power_data;
DESCRIBE switch_events;
4. PHP-Empfangsscript erstellen
Das PHP-Script empfängt die HTTP-POST-Requests von den Shelly-Geräten und schreibt die Daten in die Datenbank.
4.1 Basis-Script für Sensordaten
Erstelle die Datei /var/www/html/shelly_receive.php oder falls du mit XAMPP ein Datenbanksystem aufgebaut hat, dann den entsprechenden Pfad:
💡 Hinweis: Dieses Script unterstützt sowohl POST-Requests (von Shelly-Skripten) als auch GET-Requests (von H&T WiFi URL-Aktionen).
<?php
date_default_timezone_set('Europe/Berlin');
// Fehler-Logging aktivieren
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/apache2/shelly_errors.log');
// Datenbank-Konfiguration
define('DB_HOST', '192.168.2.xxx'); // bitte Url anpassen
define('DB_USER', 'shelly_user');
define('DB_PASS', 'xxxxxxx'); // ANPASSEN!
define('DB_NAME', 'shelly_data');
function map_event_type($raw)
{
if ($raw === null) {
return 'Unbekannt';
}
switch (strtolower($raw)) {
case 'ws_in':
case 'ws':
return 'App / Weboberfläche';
case 'btn':
case 'button':
return 'Physischer Taster';
case 'http':
return 'HTTP-Befehl';
case 'mqtt':
return 'MQTT-Befehl';
case 'timer':
return 'Timer / Auto-Off';
case 'schedule':
return 'Zeitplan';
case 'cloud':
return 'Shelly Cloud';
case 'boot':
return 'Systemstart';
default:
return ucfirst($raw); // Fallback: Original sauber anzeigen
}
}
// ---- BTHome v2 Decoder ----
function bthome_decode_ht($b64) {
$buf = base64_decode($b64, true);
if ($buf === false || strlen($buf) < 2) {
return ['ok' => false, 'err' => 'bad_base64_or_short'];
}
$info = ord($buf[0]);
$enc = ($info & 0x01) === 1;
$ver = $info >> 5;
if ($ver !== 2) {
return ['ok' => false, 'err' => 'unsupported_version'];
}
if ($enc) {
return ['ok' => false, 'err' => 'encrypted_not_supported'];
}
$i = 1;
$n = strlen($buf);
$out = ['ok' => true];
$get = function(int $bytes) use (&$i, $n, $buf) {
if ($i + $bytes > $n) return null;
$v = substr($buf, $i, $bytes);
$i += $bytes;
return $v;
};
while ($i < $n) {
$id = ord($buf[$i++]);
switch ($id) {
case 0x00: { // PID uint8
$v = $get(1);
if ($v === null) return ['ok' => false, 'err' => 'trunc_pid'];
$out['pid'] = ord($v);
break;
}
case 0x01: { // battery uint8 %
$v = $get(1);
if ($v === null) return ['ok' => false, 'err' => 'trunc_bat'];
$out['battery'] = ord($v);
break;
}
case 0x02: { // temperature int16 *0.01 °C
$v = $get(2);
if ($v === null) return ['ok' => false, 'err' => 'trunc_t01'];
$u = unpack('v', $v)[1];
if ($u & 0x8000) $u -= 65536;
$out['temperature'] = $u * 0.01;
break;
}
case 0x03: { // humidity uint16 *0.01 %
$v = $get(2);
if ($v === null) return ['ok' => false, 'err' => 'trunc_h01'];
$u = unpack('v', $v)[1];
$out['humidity'] = $u * 0.01;
break;
}
case 0x2E: { // humidity uint8 %
$v = $get(1);
if ($v === null) return ['ok' => false, 'err' => 'trunc_h08'];
$out['humidity'] = ord($v) * 1.0;
break;
}
case 0x45: { // temperature int16 *0.1 °C
$v = $get(2);
if ($v === null) return ['ok' => false, 'err' => 'trunc_t10'];
$u = unpack('v', $v)[1];
if ($u & 0x8000) $u -= 65536;
$out['temperature'] = $u * 0.1;
break;
}
default:
// Unbekannt → beenden (haben aber bereits Werte)
$i = $n;
}
}
return $out;
}
// ---- Request verarbeiten ----
// GET-Parameter (für H&T WiFi URL-Aktionen)
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET)) {
$data = [
'device_id' => $_GET['device_id'] ?? 'unknown',
'device_name' => $_GET['device_name'] ?? null,
'temperature' => $_GET['temperature'] ?? null,
'humidity' => $_GET['humidity'] ?? null,
'battery' => $_GET['battery'] ?? null,
'power' => $_GET['power'] ?? null,
'voltage' => $_GET['voltage'] ?? null,
'current' => $_GET['current'] ?? null,
'energy_total' => $_GET['energy_total'] ?? null,
'switch_state' => $_GET['switch_state'] ?? null,
// NEU: event_type aus source übernehmen
'event_type' => $_GET['source'] ?? ($_GET['event_type'] ?? null),
];
// POST-Requests
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw = file_get_contents('php://input');
$json_data = json_decode($raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
exit('Invalid JSON');
}
// BLU Gateway Daten (mit fcd2 Base64)
if (isset($json_data['fcd2']) && isset($json_data['mac'])) {
error_log("BLU Gateway: MAC=" . $json_data['mac']);
$decoded = bthome_decode_ht($json_data['fcd2']);
if (!$decoded['ok']) {
error_log("BTHome decode error: " . $decoded['err']);
http_response_code(400);
exit('BTHome decode failed');
}
error_log("BTHome decoded: " . json_encode($decoded));
$data = [
'device_id' => $json_data['mac'],
'device_name' => 'BLU_' . substr($json_data['mac'], -5),
'temperature' => $decoded['temperature'] ?? null,
'humidity' => $decoded['humidity'] ?? null,
'battery' => $decoded['battery'] ?? null
];
}
// Normale JSON-Daten (von Plug S Scripten)
else {
$data = $json_data;
}
} else {
http_response_code(405);
exit('Method Not Allowed');
}
// ---- Datenbankverbindung ----
try {
$pdo = new PDO(
'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
DB_USER,
DB_PASS,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
} catch (PDOException $e) {
error_log('DB Connection Error: ' . $e->getMessage());
http_response_code(500);
exit('Database Connection Failed');
}
// ---- Daten speichern ----
if (isset($data['temperature']) || isset($data['humidity'])) {
// Sensordaten
$stmt = $pdo->prepare(
'INSERT INTO sensor_data (device_id, device_name, temperature, humidity, battery) '
. 'VALUES (?, ?, ?, ?, ?)'
);
$success = $stmt->execute([
$data['device_id'] ?? 'unknown',
$data['device_name'] ?? null,
$data['temperature'] ?? null,
$data['humidity'] ?? null,
$data['battery'] ?? null
]);
if ($success) {
error_log("Sensor-Daten gespeichert: " . ($data['device_id'] ?? 'unknown'));
}
} elseif (isset($data['power']) || isset($data['voltage'])) {
// Leistungsdaten
$stmt = $pdo->prepare(
'INSERT INTO power_data (device_id, device_name, power, voltage, current, energy_total) '
. 'VALUES (?, ?, ?, ?, ?, ?)'
);
$success = $stmt->execute([
$data['device_id'] ?? 'unknown',
$data['device_name'] ?? null,
$data['power'] ?? null,
$data['voltage'] ?? null,
$data['current'] ?? null,
$data['energy_total'] ?? null
]);
if ($success) {
error_log("Power-Daten gespeichert: " . ($data['device_id'] ?? 'unknown'));
}
} elseif (isset($data['switch_state'])) {
// 0/1 normalisieren
$switchState = ($data['switch_state'] === 'on') ? 1 : 0;
// Event-Typ auf Klartext abbilden
$humanEvent = map_event_type($data['event_type'] ?? null);
$stmt = $pdo->prepare(
'INSERT INTO switch_events (device_id, device_name, switch_state, event_type)
VALUES (?, ?, ?, ?)'
);
$success = $stmt->execute([
$data['device_id'] ?? 'unknown',
$data['device_name'] ?? null,
$switchState,
$humanEvent, // <-- hier landet der Klartext
]);
if ($success) {
error_log("Switch-Event gespeichert: " . ($data['device_id'] ?? 'unknown'));
}
} else {
http_response_code(400);
exit('Unknown data type');
}
// Erfolg
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'Data saved']);
?>
🔒 Sicherheit: Das Script nutzt Prepared Statements zur Verhinderung von SQL-Injection. Das ist essenziell für sichere Datenbank-Operationen!
4.2 Script-Berechtigungen setzen
sudo chown www-data:www-data /var/www/html/shelly_receive.php
sudo chmod 644 /var/www/html/shelly_receive.php
5. Shelly-Skripte für Datenübertragung
Jetzt erstellen wir die Skripte auf den Shelly-Geräten, die die Daten an unser PHP-Script senden.
5.1 Shelly Plug S Gen3/4 – Leistungsdaten senden
Dieses Skript misst alle 5 Minuten Leistung, Spannung und Gesamtenergie:
// Shelly-Skript Leitungsdaten senden
// Konfiguration
let SERVER_URL = "http://192.168.2.xxx/shelly_receive.php"; //hier deine URL angeben
let DEVICE_NAME = "dein_device_name"; // Device Namen festlegen
let INTERVAL = 300 * 1000; // 5 Minuten
// Funktion zum Senden der Daten
function sendPowerData() {
let status = Shelly.getComponentStatus("switch", 0);
let data = {
device_id: Shelly.getDeviceInfo().id,
device_name: DEVICE_NAME,
power: status.apower,
voltage: status.voltage,
current: status.current,
energy_total: status.aenergy.total
};
Shelly.call("HTTP.POST", {
url: SERVER_URL,
body: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
timeout: 5
}, function(res, err) {
if (err) {
print("HTTP Error:", err);
} else {
print("Data sent:", res.code);
}
});
}
// Timer starten
Timer.set(INTERVAL, true, sendPowerData);
// Sofort beim Start ausführen
sendPowerData();
💡 Anpassung: Ersetze SERVER_URL mit der IP deines Webservers und DEVICE_NAME mit einem aussagekräftigen Namen für das Gerät.
5.2 Schalter Status senden
// Senden der Switch-Events
// =======================
// Konfiguration
// =======================
let CONFIG = {
// URL zu deiner PHP-Datei (bitte anpassen)
phpUrl: "http://192.168.2.xxx/shelly_receive.php"
};
let DEVICE_NAME = "Shelly1PM_mini";
// =======================
// Status senden
// =======================
function sendStatus(state, source) {
let info = Shelly.getDeviceInfo();
let devName = DEVICE_NAME; // fester Name, da info.name null ist
// Parameter bestehen nur aus sicheren Zeichen → kein Encoding nötig
let url = CONFIG.phpUrl +
"?device_id=" + info.id +
"&device_name=" + devName +
"&switch_state=" + state +
"&source=" + source;
Shelly.call(
"HTTP.GET",
{ url: url },
function (res, code, msg) {
if (code !== 0) {
print("HTTP-Fehler:", code, msg);
} else {
print("Status gesendet:", url);
}
}
);
}
// =======================
// Event-Handler für Schaltvorgänge
// =======================
Shelly.addStatusHandler(function (ev) {
if (ev.component === "switch:0" &&
ev.delta && typeof ev.delta.output !== "undefined") {
let state = ev.delta.output ? "on" : "off";
let source = ev.delta.source ? ev.delta.source : "unknown";
sendStatus(state, source);
}
});
// Optional: Status beim Start senden
Timer.set(3000, false, function () {
let st = Shelly.getComponentStatus("switch:0");
let state = st.output ? "on" : "off";
sendStatus(state, "boot");
});
5.3 Shelly H&T WiFi – URL-Aktionen einrichten
Wichtig: Der Shelly H&T WiFi unterstützt kein Scripting. Stattdessen nutzt er URL-Aktionen, die in der Weboberfläche oder App konfiguriert werden.
Aufwach-Intervalle:
- Batteriebetrieb: Alle 2 Stunden (um Batterie zu schonen)
- USB-Betrieb: Alle 6 Minuten (häufigere Updates)
URL-Aktion in der Weboberfläche einrichten
Damit du ohne Cloud auf den Shelly H&T WiFi zugreifen kannst, muss die rückseitige Reset-Taste einmal gedrückt werden. Bei den Plus- und Gen3-Modellen bleibt das Gerät nach dem Button-Druck für 3 Minuten aktiv und ist in dieser Zeit über IP, MQTT, BLE, WiFi, Cloud und WebSocket zum Programmieren erreichbar.
Die Dokumentation von Shelly zu diesem Gerät kannst du dir hier ansehen:
https://kb.shelly.cloud/knowledge-base/shelly-plus-h-t-web-interface-guide
https://shelly-api-docs.shelly.cloud/gen2/Devices/Gen3/ShellyHTG3
- Shelly H&T Webinterface öffnen (z.B. http://192.168.x.x)
- Menü ‚Actions‘ aufrufen
- ‚Crate Action‘ klicken
- Bei ‚Trigger‘ wählen: ‚Report‘ (wird bei jedem Aufwachen ausgelöst)
- Bei ‚Action‘ → ‚URLs‘ Tab auswählen
URL eingeben (siehe unten) - URL mit GET-Parametern:
http://192.168.2.xxx/shelly_receive.php?device_id=“12345″&device_name=Wohnzimmer&temperature=${temp}
http://192.168.2.xxx/shelly_receive.php?device_id=“12345″&device_name=Wohnzimmer&humidity=${hum}
(im H&T kann jeweils nur ein Parameter pro Aktion abgefragt werden. Deshalb 2 mal dies Aktion)
5.4 BLU Gateway – Bluetooth-Sensoren auswerten
Das BLU Gateway empfängt Daten von Bluetooth-Sensoren und leitet sie weiter:
https://kb.shelly.cloud/knowledge-base/kbsa-smart-home-automation-connecting-smart-blueto
//Shelly Skript zum Scannen der in der Nähe befindlichen BLU Sensoren
let SERVER_URL = "http://192.168.2.xxx/shelly_receive.php"; // deine URL bitte hier eintragen
// BLE-Scanner starten
BLE.Scanner.Start({
duration_ms: 30000,
active: true
});
// Ereignis-Handler für BLE-Daten
BLE.Scanner.Subscribe(function(event, result) {
if (event !== "result") return;
// Prüfe ob es ein Shelly H&T BLU ist
if (!result.service_data || !result.service_data["fcd2"]) return;
let svcData = result.service_data["fcd2"];
let data = {
device_id: result.addr,
device_name: "BLU_" + result.addr.slice(-5),
temperature: svcData.t,
humidity: svcData.rh,
battery: svcData.battery
};
Shelly.call("HTTP.POST", {
url: SERVER_URL,
body: JSON.stringify(data),
headers: {"Content-Type": "application/json"}
}, function(res, err) {
if (!err) {
print("BLU data sent");
}
});
});
⚠️ Service UUID: Die UUID fcd2 ist spezifisch für Shelly H&T BLU. Andere BLE-Geräte haben andere UUIDs.
6. System testen
Jetzt prüfen wir, ob Daten in der Datenbank ankommen:
6.1 Shelly-Skripte starten
- Öffne das Shelly Webinterface
- Gehe zu Scripts
- Füge das entsprechende Skript ein
- Aktiviere ‚Enable on Boot‘
- Klicke ‚Start‘
- Beobachte die Logs für Fehler
6.2 Datenbank prüfen
Warte 1-2 Minuten und prüfe dann die Datenbank:
mysql -u shelly_user -p shelly_data
— Sensordaten prüfen
SELECT * FROM sensor_data ORDER BY timestamp DESC LIMIT 10;

— Leistungsdaten prüfen
SELECT * FROM power_data ORDER BY timestamp DESC LIMIT 10;

— Anzahl der Einträge
SELECT COUNT(*) as total FROM sensor_data; SELECT COUNT() as total FROM power_data;
6.3 Troubleshooting
Keine Daten in der Datenbank?
- Shelly-Logs prüfen: Sind dort HTTP-Fehler zu sehen?
- PHP-Logs prüfen:
sudo tail -f /var/log/apache2/error.log
sudo tail -f /var/log/apache2/shelly_errors.log
- Netzwerk prüfen: Kann Shelly den Webserver erreichen?
# Vom Shelly aus (im Script)
print(„Testing connection to“, SERVER_URL);
- Manueller Test mit curl:
curl -X POST http://192.168.2.100/shelly_receive.php \
-H „Content-Type: application/json“ \
-d ‚{„device_id“:“test“,“temperature“:22.5,“humidity“:60}‘
7. Einfache Datenabfragen
Jetzt wo Daten fließen, hier ein paar nützliche SQL-Abfragen zum Testen:
7.1 Aktuelle Werte aller Geräte
SELECT
device_name,
temperature,
humidity,
battery,
timestamp
FROM sensor_data
WHERE timestamp > NOW() – INTERVAL 5 MINUTE
ORDER BY timestamp DESC;
7.2 Durchschnittswerte der letzten Stunde
SELECT
device_name,
ROUND(AVG(temperature), 2) as avg_temp,
ROUND(AVG(humidity), 2) as avg_humidity
FROM sensor_data
WHERE timestamp > NOW() – INTERVAL 1 HOUR
GROUP BY device_name;

7.3 Energieverbrauch pro Tag
SELECT
DATE(timestamp) as day,
device_name,
MAX(energy_total) – MIN(energy_total) as daily_kwh
FROM power_data
WHERE timestamp > NOW() – INTERVAL 7 DAY
GROUP BY DATE(timestamp), device_name
ORDER BY day DESC;

7.4 Min/Max-Werte
SELECT
device_name,
MIN(temperature) as min_temp,
MAX(temperature) as max_temp,
MIN(humidity) as min_humidity,
MAX(humidity) as max_humidity
FROM sensor_data
WHERE timestamp > NOW() – INTERVAL 24 HOUR
GROUP BY device_name;

✅ Erfolg: Wenn diese Abfragen Daten liefern, läuft dein System perfekt! Im nächsten Artikel erstellen wir daraus schöne Dashboards mit Grafiken.
8. Wartung und Optimierung
Damit dein System langfristig gut läuft:
8.1 Alte Daten automatisch löschen
Erstelle einen Cronjob zum Löschen alter Daten:
#!/bin/bash mysql -u shelly_user -p'dein_passwort' shelly_data <<EOF DELETE FROM sensor_data WHERE timestamp < NOW() - INTERVAL 90 DAY; DELETE FROM power_data WHERE timestamp < NOW() - INTERVAL 90 DAY; DELETE FROM switch_events WHERE timestamp < NOW() - INTERVAL 30 DAY; OPTIMIZE TABLE sensor_data; OPTIMIZE TABLE power_data; OPTIMIZE TABLE switch_events; EOF
Ausführbar machen und Cronjob erstellen:
sudo chmod +x /usr/local/bin/cleanup_shelly_data.sh
Cronjob: Jeden Sonntag um 3 Uhr
sudo crontab -e
Folgende Zeile hinzufügen:
0 3 * * 0 /usr/local/bin/cleanup_shelly_data.sh
Was kommt als Nächstes?
In den kommenden Artikeln dieser Serie auf diytechadventures.de/projekte zeige ich dir:
- Webinterface: Dashboards für Visualisierung und Steuerung
- BLU Gateway Scripting: Bluetooth-Sensoren auswerten und weiterleiten
- Erweiterte Automationen: Komplexe Szenarien aus meinem Bungalow-Projekt
- ThingSpeak-Integration: Cloud-Visualisierung für Fernzugriff
Das war ein Hammer DIYTechAdventure. Schreibe mir, ob du alles nachvollziehen konntest. Anregungen nehme ich ebenfalls gerne entgegen. Freue dich weiter auf den nächsten Beitrag, der sich um die grafische Ausgabe der Sensordaten kümmern wird.