Dieses Projekt ist aus einem realen Dilemma des digitalen Alltags entstanden. In einer Zeit, in der Bildschirmzeit, Mediensucht und die ständige Verfügbarkeit von Inhalten grosse Herausforderungen in der Erziehung darstellen, ist stromweg weit mehr als eine technische Spielerei.
Ein technisches "Abschalten" von aussen sollte eigentlich NIE notwendig sein. Kommunikation, Vertrauen und das Pflegen anderer Hobbies (Sport, Natur, analoge Spiele) müssen immer an erster Stelle stehen.
Dennoch kennen alle Eltern die Situation: Wenn Absprachen nicht fruchten und die digitale Suchtspirale die Oberhand gewinnt, braucht es eine klare, physische Grenze. stromweg dient als:
- Sicherheitsnetz: Um Hardwareschäden beim harten Stromauszug zu vermeiden.
- Lernobjekt: Gemeinsam gebaut, um zu verstehen, wie Befehle und Regeln funktionieren.
- Letztes Mittel: Wenn die Konsequenz eines "Strom-Wegs" eintritt, dann soll sie wenigstens sauber und kontrolliert ablaufen.
Wir nutzen eine Zwei-Kabel-Loesung, um Signalstörungen zwischen der 4A-Last und der Datenleitung zu vermeiden.
| RJ45 Paar (Farbe) | Funktion | Verbindung im Laptop |
|---|---|---|
| Orange / Weiss | USB Data (D+ / D-) | Webcam-Stecker Pin D+ & D- |
| Grün / Weiss | USB Power (5V / GND) | Webcam-Stecker Pin VCC & GND |
| Blau / Weiss | ESP-Signal | ESP32 GPIO 4 & GND |
Hier findest du alle visuellen Details zum Nachbauen:
Hier findest du die Links zu den vollständigen Quelldateien im Repository:
| Datei | Zweck | Ziel-Ort |
|---|---|---|
| waechter.ino | ESP32 Steuersoftware (Profi-Erzaehler) | ESP32 Board |
| listener.py | Python-Shutdown-Empfaenger | ~/.local/bin/ |
| listener.service | Systemd Automatisierung | /etc/systemd/system/ |
/* * STROM-WEG ADAPTER - DER WAECHTER (v1.0) */
const int triggerPin = 4;
const long warteZeit = 5000;
const long gedankenPause = 20000;
unsigned long letzteAktionZeit = 0;
unsigned long letzteGedankenZeit = 0;
int geschichtenZaehler = 0;
bool befehlGesendet = false;
void setup() {
delay(5000);
Serial.begin(9600);
Serial.flush();
for(int i=0; i<10; i++) { Serial.println(""); }
pinMode(triggerPin, INPUT_PULLUP);
Serial.println("******************************************");
Serial.println("* stromweg - DER WAECHTER (v1.0) *");
Serial.println("******************************************");
letzteGedankenZeit = millis();
}
void loop() {
unsigned long aktuelleZeit = millis();
int schalterZustand = digitalRead(triggerPin);
if (aktuelleZeit - letzteGedankenZeit >= gedankenPause && !befehlGesendet) {
letzteGedankenZeit = aktuelleZeit;
switch (geschichtenZaehler) {
case 0: Serial.println("[LOG] Ich bewache Pin 4."); break;
case 1: Serial.println("[LOG] Webcam-Leitung aktiv."); break;
case 2: Serial.println("[LOG] Zorin OS geht bald ins Bett."); break;
}
geschichtenZaehler = (geschichtenZaehler + 1) % 3;
delay(50);
}
if (schalterZustand == LOW && !befehlGesendet) {
letzteAktionZeit = aktuelleZeit;
befehlGesendet = true;
Serial.println("SHUTDOWN_NOW");
delay(100);
}
if (befehlGesendet && (aktuelleZeit - letzteAktionZeit >= warteZeit)) {
befehlGesendet = false;
letzteGedankenZeit = aktuelleZeit;
}
}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import serial
import os
import time
# --- EINSTELLUNGEN ---
SERIAL_PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
COMMAND = "SHUTDOWN_NOW"
USER_NAME = "sysadmin"
USER_ID = "1000"
def send_single_alert():
title = "🛑 STROM-WEG ALARM"
msg = "FEIERABEND! Der Computer wird in 60 Sekunden ausgeschaltet. SPEICHERE SOFORT!"
# Der Befehl für die grafische Benachrichtigung
cmd = (
f"sudo -u {USER_NAME} "
f"DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{USER_ID}/bus "
f"notify-send '{title}' '{msg}' --urgency=critical --icon=dialog-warning"
)
os.system(cmd)
# Text-Nachricht für die Konsole
os.system(f"echo '{msg}' | wall")
def start_listening():
print(f"--- stromweg: Listener v1.1.9 aktiv ---")
try:
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(2)
ser.reset_input_buffer()
while True:
if ser.in_waiting > 0:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if line == COMMAND:
print(f"[ALARM] Signal erkannt! 60s Countdown läuft...")
# Einmalige Warnung absetzen
send_single_alert()
# Shutdown in 1 Minute einplanen
os.system("sudo shutdown -h +1")
# 120s Sperre, um Rescheduling-Schleifen zu verhindern
print("Sperre aktiv: System fährt herunter...")
time.sleep(120)
time.sleep(0.5)
except Exception as e:
print(f"[FEHLER] {str(e)}")
if __name__ == "__main__":
start_listening()
In diesem Abschnitt richten wir den "Lauscher" (das Python-Skript) und den dazugehörigen System-Dienst ein, damit dein Laptop auf das Signal des Wächters reagieren kann.
Zuerst erstellen wir den notwendigen Ordner in deinem Benutzerverzeichnis und installieren die Bibliothek für die serielle Kommunikation.
Bash
mkdir -p ~/.local/bin && sudo apt update && sudo apt install python3-serial -y
# Deinstallation: sudo apt remove python3-serial -y
Wir legen die Datei direkt an deinem Zielort an.
Bash
nano ~/.local/bin/listener.py
# Deinstallation: rm ~/.local/bin/listener.py
Vorgehensweise: Kopiere den vollständigen Code der
listener.pyin das schwarze Fenster. Drücke zum Speichern Strg+O und Enter. Mit Strg+X kehrst du zum Terminal zurück.
Damit das Skript mit Root-Rechten im Hintergrund läuft, erstellen wir eine Dienst-Datei im Systemordner.
Bash
sudo nano /etc/systemd/system/listener.service
# Deinstallation: sudo rm /etc/systemd/system/listener.service
Vorgehensweise: Kopiere den Inhalt der
listener.servicein den Editor. WICHTIG: Ersetze in der ZeileExecStartden PlatzhalterDEIN_BENUTZERNAMEdurch deinen echten Namen (z.B.albertuszerk). Speichere mit Strg+O, bestätige mit Enter und beende mit Strg+X.
Damit das System den neuen Dienst erkennt und sofort ausführt, nutzen wir folgende Befehlskette:
Bash
sudo systemctl daemon-reload && sudo systemctl enable listener.service && sudo systemctl start listener.service
# Deinstallation: sudo systemctl stop listener.service && sudo systemctl disable listener.service && sudo systemctl daemon-reload
Um sicherzugehen, dass alles korrekt funktioniert, kannst du den Status abfragen:
Bash
sudo systemctl status listener.service
Wenn dort in grüner Schrift "active (running)" steht, lauscht dein Haus Zorin nun offiziell auf den Wächter am Gartenzaun.
Um Datenverlust zu vermeiden, muss die Zeitverzögerung exakt eingehalten werden:
-
Aktion: Schalte Kanal 2 (Signal) auf AUS.
-
Warten: 45 Sekunden (Laptop fährt kontrolliert runter).
-
Aktion: Schalte Kanal 1 (Hauptstrom 4A) auf AUS.
Stell dir vor, dein Laptop ist ein riesiges, gemütliches Haus namens Zorin. In diesem Haus arbeiten hunderte kleine Helfer (die Programme). Sie räumen auf, schreiben Briefe oder spielen Musik.
Tip
Draussen am Gartenzaun sitzt unser kleiner Freund, der ESP32. Er ist der Waechter. Er hat eine ganz wichtige Aufgabe: Er passt auf, ob du den grossen "Feierabend-Knopf" (den Tuya-Switch) drückst.
Sobald du drückst, greift der Waechter zu seinem Funkgerät und ruft ganz laut in das USB-Kabel hinein: SHUTDOWN_NOW!. Das USB-Kabel ist wie eine geheime Rohrpost, die direkt in das Haus Zorin führt.
Important
Drinnen im Haus Zorin sitzt ein spezieller Helfer direkt am Ende der Rohrpost-Leitung. Das ist unser Python-Skript. Er macht den ganzen Tag nichts anderes, als sein Ohr an das Rohr zu halten. Sobald er das Wort SHUTDOWN_NOW hört, weiss er: "Oha, jetzt wird es ernst!"
Caution
Jetzt kommt der Moment mit os.system("sudo shutdown -h now"). Das ist für den Python-Helfer so, als würde er eine goldene Glocke im Haus läuten und über die Lautsprecher rufen:
"Achtung an alle Helfer! Sofort alles stehen und liegen lassen, Fenster schliessen, Licht ausmachen und ab ins Bett!"
| 🧩 Begriff | 📖 Bedeutung | 👑 Der "Chef-Faktor" |
|---|---|---|
sudo |
Der magische Ausweis | "Ich darf das, ich bin der Chef!" |
shutdown -h |
Die Abschliess-Aktion | "Haus abschliessen!" |
now |
Der Zeitplan | "Nicht erst morgen, sondern SOFORT!" |
| 🧩 Code | 📖 Bedeutung |
|---|---|
Serial.println |
"Ich rufe eine Nachricht in die Leitung!" |
SHUTDOWN_NOW |
Das geheime Codewort. |
os.system |
Der Chef-Befehl an den Computer. |
sudo shutdown |
"Alle Fenster zu, Lichter aus, wir gehen schlafen!" |
Lizenz: CC BY-NC-SA 4.0
Erstellt von Albertus Zerk in Zusammenarbeit mit Gemini. Version 1.0 (Final) | Maerz 2026.






