Files
2026-06-23 15:30:55 +02:00

5.7 KiB

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

+-------------------+
| openHAB / Browser |
+-------------------+
          |
          v
+-------------------+
| Python Web API    |
| script-api.py     |
+-------------------+
          |
          v
+-------------------+
| ir-ctl            |
| Linux IR Subsystem|
+-------------------+
          |
          v
+-------------------+
| IR Sender GPIO    |
+-------------------+

Voraussetzungen

Pakete installieren

sudo apt update
sudo apt install -y ir-ctl python3

Optional:

sudo apt install -y v4l-utils

Dateien

/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

cd /home/timm/IRSender

chmod +x script-api.py

nohup python3 -u script-api.py ./commands.json >> apiout.log 2>&1 &

Stoppen

pkill -f script-api.py

Logs anzeigen

tail -f /home/timm/IRSender/apiout.log

Health Check

curl http://<rpi-ip>:8080/health

Antwort:

{
  "ok": true
}

Weboberfläche

http://<rpi-ip>:8080/

Die Weboberfläche benötigt keinen Login.

Nur Commands mit:

"web_enabled": true

werden angezeigt.


REST API

Kommando ausführen

Request

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

{
  "ok": true,
  "request_id": "f8d7f6a1",
  "command_id": "lirc-tv-power",
  "exit_code": 0,
  "timed_out": false,
  "duration_ms": 124,
  "stdout": "",
  "stderr": ""
}

Kommandos anzeigen

curl http://<rpi-ip>:8080/commands

commands.json

Beispiel

{
  "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

"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

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

channels:
  - id: lirc_tv_power
    channelTypeUID: http:switch
    label: TV Power

    configuration:
      mode: WRITEONLY
      commandExtension: /run/lirc-tv-power

      onValue: {"args":{}}
      offValue: {"args":{}}

Item

Switch IR_TV_Power "TV Power"
  { channel="http:url:ir_sender:lirc_tv_power" }

Systemd Service

Service Datei

[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

sudo nano /etc/systemd/system/rpi-ir-api.service

Service einfügen.

Dann:

sudo systemctl daemon-reload
sudo systemctl enable --now rpi-ir-api

Service Status

sudo systemctl status rpi-ir-api

Service Logs

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:

"command": ["bash", "-c", "{user_input}"]

oder:

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:

-H "X-API-Key: change-this-global-api-key"

400 invalid json

Body ist kein gültiges JSON.

Korrekt:

{"args":{}}

500 command failed

ir-ctl oder Datei prüfen:

ir-ctl --send /home/timm/IRSender/LichtEin.txt

Permission denied

GPIO / IR Rechte prüfen.

Test:

sudo ir-ctl --send /home/timm/IRSender/LichtEin.txt

Falls nur mit sudo funktioniert:

sudo usermod -aG video timm

Danach neu anmelden.


Backup

Wichtig sichern:

script-api.py
commands.json
*.txt

Lizenz

Internes Projekt.