Files
IrSender2/README.md
T
2026-06-23 15:30:55 +02:00

465 lines
5.7 KiB
Markdown

# Raspberry Pi IR Web API
Kleine Python Web API für Raspberry Pi zur Ausführung definierter IR-Kommandos mittels `ir-ctl`.
Features:
- REST API mit API-Key
- Kleine Weboberfläche ohne Login
- JSON-basierte Konfiguration
- Definierte Kommandos
- Keine Shell Injection (`shell=False`)
- Timeout pro Kommando
- Logging
- Geeignet für openHAB HTTP Binding
- Kein Docker notwendig
---
# Architektur
```text
+-------------------+
| openHAB / Browser |
+-------------------+
|
v
+-------------------+
| Python Web API |
| script-api.py |
+-------------------+
|
v
+-------------------+
| ir-ctl |
| Linux IR Subsystem|
+-------------------+
|
v
+-------------------+
| IR Sender GPIO |
+-------------------+
```
---
# Voraussetzungen
## Pakete installieren
```bash
sudo apt update
sudo apt install -y ir-ctl python3
```
Optional:
```bash
sudo apt install -y v4l-utils
```
---
# Dateien
```text
/home/timm/IRSender/
├── script-api.py
├── commands.json
├── apiout.log
├── blue.txt
├── brighter.txt
├── darker.txt
├── defaultColor.txt
├── fade.txt
├── green.txt
├── LichtAus.txt
├── LichtEin.txt
├── Nachtlicht.txt
├── off.txt
├── on.txt
├── purple.txt
├── red.txt
├── smooth.txt
├── white.txt
└── yellow.txt
```
---
# Starten
```bash
cd /home/timm/IRSender
chmod +x script-api.py
nohup python3 -u script-api.py ./commands.json >> apiout.log 2>&1 &
```
---
# Stoppen
```bash
pkill -f script-api.py
```
---
# Logs anzeigen
```bash
tail -f /home/timm/IRSender/apiout.log
```
---
# Health Check
```bash
curl http://<rpi-ip>:8080/health
```
Antwort:
```json
{
"ok": true
}
```
---
# Weboberfläche
```text
http://<rpi-ip>:8080/
```
Die Weboberfläche benötigt keinen Login.
Nur Commands mit:
```json
"web_enabled": true
```
werden angezeigt.
---
# REST API
## Kommando ausführen
### Request
```bash
curl -s -X POST \
-H "X-API-Key: change-this-global-api-key" \
-H "Content-Type: application/json" \
http://<rpi-ip>:8080/run/lirc-tv-power \
-d '{"args":{}}'
```
### Response
```json
{
"ok": true,
"request_id": "f8d7f6a1",
"command_id": "lirc-tv-power",
"exit_code": 0,
"timed_out": false,
"duration_ms": 124,
"stdout": "",
"stderr": ""
}
```
---
# Kommandos anzeigen
```bash
curl http://<rpi-ip>:8080/commands
```
---
# commands.json
## Beispiel
```json
{
"host": "0.0.0.0",
"port": 8080,
"commands": {
"lirc-tv-power": {
"description": "Send TV power button",
"web_title": "TV Power",
"web_enabled": true,
"api_key": "change-this-global-api-key",
"timeout_seconds": 10,
"command": [
"ir-ctl",
"--send",
"/home/timm/IRSender/LichtEin.txt"
],
"args": {}
}
}
}
```
---
# Neues Kommando hinzufügen
## Beispiel
```json
"my-command": {
"description": "Example command",
"web_title": "Example",
"web_enabled": true,
"api_key": "change-this-global-api-key",
"timeout_seconds": 10,
"command": [
"ir-ctl",
"--send",
"/home/timm/IRSender/example.txt"
],
"args": {}
}
```
---
# openHAB Integration
## HTTP Thing
### Thing
```text
UID: http:url:ir_sender
label: IR Sender
thingTypeUID: http:url
configuration:
baseURL: http://<rpi-ip>:8080
commandMethod: POST
contentType: application/json
headers:
- X-API-Key=change-this-global-api-key
```
---
## Channel
```text
channels:
- id: lirc_tv_power
channelTypeUID: http:switch
label: TV Power
configuration:
mode: WRITEONLY
commandExtension: /run/lirc-tv-power
onValue: {"args":{}}
offValue: {"args":{}}
```
---
## Item
```text
Switch IR_TV_Power "TV Power"
{ channel="http:url:ir_sender:lirc_tv_power" }
```
---
# Systemd Service
## Service Datei
```ini
[Unit]
Description=Raspberry Pi IR Web API
After=network-online.target
[Service]
Type=simple
User=timm
WorkingDirectory=/home/timm/IRSender
ExecStart=/usr/bin/python3 /home/timm/IRSender/script-api.py /home/timm/IRSender/commands.json
Restart=always
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=false
[Install]
WantedBy=multi-user.target
```
---
## Installation
```bash
sudo nano /etc/systemd/system/rpi-ir-api.service
```
Service einfügen.
Dann:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now rpi-ir-api
```
---
# Service Status
```bash
sudo systemctl status rpi-ir-api
```
---
# Service Logs
```bash
journalctl -u rpi-ir-api -f
```
---
# Sicherheit
## Implementiert
- Keine Shell-Ausführung
- Keine freien Kommandos
- API-Key Prüfung
- JSON Validierung
- Timeout pro Kommando
- Regex Validierung
- HTML Escaping
- CSRF Token für Web UI
- Security Headers
---
# Wichtig
## Niemals erlauben:
```json
"command": ["bash", "-c", "{user_input}"]
```
oder:
```python
shell=True
```
Sonst wird aus der Lichtsteuerung sehr schnell eine Fernwartung mit Spezialeffekten.
---
# Troubleshooting
## 403 invalid api key
API Key falsch oder Header fehlt.
Prüfen:
```bash
-H "X-API-Key: change-this-global-api-key"
```
---
## 400 invalid json
Body ist kein gültiges JSON.
Korrekt:
```json
{"args":{}}
```
---
## 500 command failed
`ir-ctl` oder Datei prüfen:
```bash
ir-ctl --send /home/timm/IRSender/LichtEin.txt
```
---
## Permission denied
GPIO / IR Rechte prüfen.
Test:
```bash
sudo ir-ctl --send /home/timm/IRSender/LichtEin.txt
```
Falls nur mit sudo funktioniert:
```bash
sudo usermod -aG video timm
```
Danach neu anmelden.
---
# Backup
Wichtig sichern:
```text
script-api.py
commands.json
*.txt
```
---
# Lizenz
Internes Projekt.