Raspberry-Pi/alarm.py
Adu Alex Göllnitz 5c42e26d41 Dateien nach "/" hochladen
Alle im Anhang ersichtlichen Dateien wurden selbst erstellt und getestet.

Sie dienen dem nutzen des Raspberry-Pi Projekts des HS25 CDS Computer-Sciences Moduls.
2025-12-17 16:53:39 +01:00

293 lines
8.1 KiB
Python

from gpiozero import MotionSensor, Buzzer, LED
from flask import Flask, render_template_string, redirect, url_for, request
import threading
import time as time_module
import requests
from datetime import datetime, time as dtime
# GPIO-Pins
PIR_PIN = 17
BUZZER_PIN = 18
LED_PIN = 27
PIN_CODE = "1811"
# Telegram-Konfiguration
TELEGRAM_BOT_TOKEN = "8295131851:AAEGTotKaTzIvAxqxcNYk90zNOFx12vVNfk"
TELEGRAM_CHAT_ID = "8428261562"
# Raspberry-PI Anschlusssensoren
pir = MotionSensor(PIR_PIN)
buzzer = Buzzer(BUZZER_PIN)
led = LED(LED_PIN)
app = Flask(__name__)
manual_armed = False # manuell scharf/unscharf
night_override_off = False # Nachtmodus für diese Nacht deaktiviert
last_event = None
event_log = []
def send_telegram_message(text: str):
# Schickt eine Nachricht über das Telegram-Bot-API.
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
print("Telegram nicht konfiguriert, überspringe Nachricht.")
return
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
try:
response = requests.post(url, json={
"chat_id": TELEGRAM_CHAT_ID,
"text": text,
})
if not response.ok:
print("Telegram-Fehler:", response.text)
except Exception as e:
print("Fehler beim Senden an Telegram:", e)
def log_event(text: str):
# Speichert Ereignis mit Zeitstempel und gibt es aus.
global last_event, event_log
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
entry = f"[{ts}] {text}"
last_event = entry
event_log.insert(0, entry)
event_log = event_log[:20]
print(entry)
def alarm_on():
buzzer.on()
led.on()
def alarm_off():
buzzer.off()
led.off()
# Zeitfenster geht über Mitternacht: [22:30, 24:00) U [00:00, 06:00)
def is_night_window():
now = datetime.now().time()
start = dtime(22, 30)
end = dtime(6, 0)
return now >= start or now < end
def is_system_armed():
# Effektiver Scharf-Status:
# - Wenn Nachtfenster aktiv und nicht übersteuert → scharf
# - Sonst nach manuellem Status
if is_night_window() and not night_override_off:
return True
return manual_armed
def monitor_motion():
# Läuft in einem Hintergrundthread und überwacht den PIR.
global night_override_off
while True:
try:
# Nacht-Override zurücksetzen, wenn man nicht mehr im Nachtfenster ist
if not is_night_window() and night_override_off:
night_override_off = False
log_event("Nacht-Override zurückgesetzt (neuer Tag).")
if pir.motion_detected:
if is_system_armed():
log_event("Bewegung erkannt! Alarm ausgelöst.")
alarm_on()
send_telegram_message("Bewegung erkannt! Alarm auf deinem Raspberry Pi!")
time_module.sleep(5) # Alarmdauer
alarm_off()
else:
log_event("Bewegung erkannt, aber System ist UNSCHARF.")
time_module.sleep(2)
time_module.sleep(0.1)
except Exception as e:
print("Fehler in monitor_motion:", e)
time_module.sleep(1)
# Weboberfläche (Flask)
HTML_TEMPLATE = """
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Raspberry Pi Alarmanlage</title>
<style>
body { font-family: sans-serif; max-width: 700px; margin: 20px auto; }
.status { padding: 10px; border-radius: 5px; margin-bottom: 10px; }
.armed { background: #ffdddd; }
.disarmed { background: #ddffdd; }
.buttons form {
display: inline-block;
margin-right: 10px;
margin-top: 5px;
}
button {
padding: 8px 12px;
border-radius: 4px;
border: 1px solid #333;
background: #f5f5f5;
cursor: pointer;
}
input[type=password] {
padding: 6px;
margin-right: 5px;
}
.log { margin-top: 20px; }
li { margin-bottom: 4px; }
.small { font-size: 0.9em; color: #555; }
</style>
</head>
<body>
<h1>Raspberry Pi Alarmanlage</h1>
<div class="status {{ 'armed' if armed else 'disarmed' }}">
<strong>Status:</strong>
{% if armed %}
SCHARF
{% if auto_night and not manual_armed and not night_override_off %}
(Nachtmodus)
{% elif manual_armed %}
(manuell)
{% endif %}
{% else %}
UNSCHARF
{% if auto_night and night_override_off %}
(Nachtmodus übersteuert)
{% endif %}
{% endif %}
<br>
<span class="small">
Nachtmodus aktiv von 22:30 bis 06:00 Uhr.
{% if auto_night %}
(Gerade im Nachtzeitfenster)
{% else %}
(Aktuell außerhalb des Nachtzeitfensters)
{% endif %}
</span><br>
{% if last_event %}
<strong>Letztes Ereignis:</strong> {{ last_event }}
{% else %}
<strong>Letztes Ereignis:</strong> Noch keins
{% endif %}
</div>
<h2>Steuerung</h2>
<p class="small">Für alle Aktionen wird der PIN benötigt.</p>
<div class="buttons">
{% if not armed %}
<form method="post" action="{{ url_for('arm') }}">
<input type="password" name="pin" placeholder="PIN" required>
<button type="submit">Scharf schalten</button>
</form>
{% else %}
<form method="post" action="{{ url_for('disarm') }}">
<input type="password" name="pin" placeholder="PIN" required>
<button type="submit">Entschärfen</button>
</form>
{% endif %}
<form method="post" action="{{ url_for('test_alarm') }}">
<input type="password" name="pin" placeholder="PIN" required>
<button type="submit">Test-Alarm</button>
</form>
</div>
<div class="log">
<h2>Ereignis-Log</h2>
<ul>
{% for e in event_log %}
<li>{{ e }}</li>
{% endfor %}
</ul>
</div>
</body>
</html>
"""
@app.route("/")
def index():
armed = is_system_armed()
auto_night = is_night_window()
return render_template_string(
HTML_TEMPLATE,
armed=armed,
auto_night=auto_night,
manual_armed=manual_armed,
night_override_off=night_override_off,
last_event=last_event,
event_log=event_log
)
@app.route("/arm", methods=["POST"])
def arm():
global manual_armed, night_override_off
pin = request.form.get("pin", "")
if pin != PIN_CODE:
log_event("Falscher PIN beim Scharf schalten (Web).")
return redirect(url_for('index'))
manual_armed = True
night_override_off = False # wenn manuell scharf, Nacht-Override zurücksetzen
log_event("System manuell scharf geschaltet (Web).")
return redirect(url_for('index'))
@app.route("/disarm", methods=["POST"])
def disarm():
global manual_armed, night_override_off
pin = request.form.get("pin", "")
if pin != PIN_CODE:
log_event("Falscher PIN beim Entschärfen (Web).")
return redirect(url_for('index'))
manual_armed = False
alarm_off()
if is_night_window():
night_override_off = True # Nacht Nachtmodus aus
log_event("System entschärft, Nachtmodus für diese Nacht übersteuert (Web).")
else:
log_event("System entschärft (Web).")
return redirect(url_for('index'))
@app.route("/test", methods=["POST"])
def test_alarm():
pin = request.form.get("pin", "")
if pin != PIN_CODE:
log_event("Falscher PIN beim Test-Alarm (Web).")
return redirect(url_for('index'))
log_event("Test-Alarm ausgelöst (Web).")
alarm_on()
send_telegram_message("Test-Alarm vom Raspberry Pi.")
time_module.sleep(3)
alarm_off()
return redirect(url_for('index'))
def main():
# Hintergrundthread für Bewegungsüberwachung starten
t = threading.Thread(target=monitor_motion, daemon=True)
t.start()
# Flask-Webserver starten
app.run(host="0.0.0.0", port=5000)
if __name__ == "__main__":
main()