OpenWrt – WLAN zeitgesteuert mit UCI und Crontab

14 January 2013

Ich habe mir vor ein paar Wochen einen WLAN Access Point gekauft und auf diesen gleich die freie Firmware OpenWrt geflashed.

Nun wollte ich die Signalstärke des WLAN je nach Uhrzeit regeln oder dieses komplett ausschalten, um Strom zu sparen. Unter OpenWrt geht das relativ einfach mit den richtigen UCI-Befehlen in Kombination mit Crontab.

Die wichtigsten UCI-Befehle auf einen Blick

UCI-Befehl zum steuern der Sendeleistung in dBm:

uci seti wireless.@wifi-device[0].txpower=10; uci commit wireless; wifi

UCI-Befehl zum deaktvieren der WLAN-Schnittstelle:

uci set wireless.@wifi-device[0].disabled=1; uci commit wireless; wifi

UCI-Befehl zum aktivieren der WLAN-Schnittstelle:

uci set wireless.@wifi-device[0].disabled=0; uci commit wireless; wifi

@wifi-device[0] steht für das erste wifi-iface in /etc/config/wireless. Nutzt man Multi-SSID, so kann es auch @wifi-device[1] oder @wifi-device[2] sein.

Danach kann man mit txpower=WERT die Signalstärke in dBm festlegen. In Deutschland kann man alle Werte von 0 (1 mW) bis 20 (100 mW) eintragen. In meinem Fall möchte ich zu Stoßzeiten die Transmit Power auf 19 dBm (79 mW) halten und in ruhigen Zeiten bei 10 dBm (10 mW).

Die Konfiguration von Crontab:

In LuCI findet man unter dem Reiter ‘System‘ –> ‘Scheduled Tasks‘ ein Eingabefeld, welches der Datei /etc/crontab/root entspricht. Diese Datei lässt sich selbstverstendlich auch von einer Shell z.B. mit vi oder nano bearbeiten.

Hier können wir nun unsere gewünschten Zeiten im Crontab Format eintragen.

#Minuten #Stunden #Tag #Monat #Wochentag #Befehl
0 6 * * 1-5 uci set wireless.@wifi-device[0].txpower=19; uci commit wireless; wifi 
0 23 * * 1-5 uci set wireless.@wifi-device[0].txpower=10; uci commit wireless; wifi

Die erste Zeile setzt die Transmit Power der WLAN-Schnittstelle ‘@wifi-device[0]’ jeden Montag – Freitag um 6:00 Uhr auf 19dBm.
Die zweite Zeile setzt die Transmit Power der WLAN-Schnittstelle ‘@wifi-device[0]’ jeden Montag – Freitag um 23:00 Uhr auf 10dBm.

Wichtig: Sonntag entspricht dem Wochentag 0 und nicht 7! Trägt man 7 ein, so wird der Eintrag und alle folgenden von Crontab unter OpenWrt einfach ignoriert.

Cron-Daemon aktivieren:

/etc/init.d/cron enable && /etc/init.d/cron start

Alternativ: WLAN nur ausschalten, wenn keine Clients mehr verbunden sind

Manchmal ist man doch noch etwas länger online und möchte nicht, dass das WLAN einfach ausgeschaltet wird. Andere Router wie beispielsweise eine Fritz!Box oder ein Speedport können das WLAN zu einer vorgegeben Uhrzeit ausschalten, warten aber noch bis sich alle Clients abgemeldet haben. Unter OpenWrt können wir das mit einem einfachen Shell-Skript lösen:

Zunächst legen wir die Datei /root/wlanToggle.sh an:

touch /root/wlanToggle.sh

Danach füllen wir die Datei /root/wlanToggle.sh mit folgendem Shell-Skript:

#!/bin/sh
PATH=/usr/bin:/usr/sbin:/sbin:/bin
WIFI_DEVICE=$2
WIFI_UCI_DEVICE=$3
PATH_TO_STATUS=/root/wlanstatus_$WIFI_DEVICE
WAIT=300
 
case "$1" in
    stop)
        echo "0" > $PATH_TO_STATUS
        STATUS=0
        while [ "$STATUS" = "0" ]
        do
            DUMP=$(iw dev $WIFI_DEVICE station dump)
            if [ -z "$DUMP" ]; then
                echo "Es sind keine Clients mehr Verbunden. WLAN-Schnittstelle $WIFI_DEVICE herunterfahren."
                uci set wireless.$WIFI_UCI_DEVICE.disabled=1; uci commit wireless; wifi
                exit 0
            fi
            echo "Es sind noch Clients mit $WIFI_UCI_DEVICE verbunden. Warte $WAIT Sekunden..."
            sleep $WAIT
            STATUS=$(cat $PATH_TO_STATUS)
        done
        echo "WLAN wurde vom Skript erneut eingeschalten. Beende Deaktivierungsversuch."
        exit 0
        ;;
 
    start)
        echo "1" > $PATH_TO_STATUS
        uci set wireless.$WIFI_UCI_DEVICE.disabled=0; uci commit wireless; wifi
        exit 0
        ;;
     
    force-stop)
        echo "0" > $PATH_TO_STATUS
        uci set wireless.$WIFI_UCI_DEVICE.disabled=1; uci commit wireless; wifi
        exit 0
        ;;
 
esac

Und machen sie ausführbar mit:

chmod +x /root/wlanToggle.sh

Das Skript kann mittels start, stop und force-stop Schalter gesteuert werden. Außerdem muss das WLAN-Device und die WLAN-Schnittstelle angegeben werden (siehe unten).

Der “Stop”-Schalter prüft zunächst ob bereits das Startskript ausgeführt wurde. Dies kann insbesondere dann vorkommen, wenn mindestens ein Client die ganze Nacht über angemeldet war und der Cronjob das Interface wieder starten möchte. Falls wir die WLAN-Schnittstelle also immernoch herunterfahren möchten prüft das Skript ob noch Clients mit der Schnittstelle verbunden sind. Falls keine Clients mehr verbunden sind wird die entsprechende Schnittstelle mit dem alt bekannten UCI Befehl heruntergefahren und das Skript beendet. Andernfalls wartet das Skript eine bestimmte Zeitspanne ab und beginnt von neuem.

Der “Start”-Schalter überschreibt zunächst die Statusvariable, damit ein etwaig laufendes Stopp-Skript beendet wird. Danach aktiviert es die gewünschte Schnittstelle und beendet das Skript.

Der “Force-Stop”-Schalter fährt die gewünschte Schnittstelle direkt herunter. Ein etwaig laufendes Stopp-Skript wird automatisch beendet, wenn nach Ablauf von $WAIT erneut nach verbundenen Clients gesucht wird (da keine Clients mehr verbunden sind, wenn die Schnittstelle bereits heruntergefahren wurde).

Letztendlich habe ich das Skript noch für Multi-SSID angepasst. Da man auf einem WLAN-Device mehrere WLAN-Schnittstellen betreiben kann (Multi-SSID, z.B. Privates- und Gastnetz) sollen diese auch einzeln steuerbar sein.

 

Die Benutzung des Skripts im Standardfall mit einer SSID ist wie folgt:

./wlanToggle.sh start wlan0 @wifi-iface[0]

In einer Multi-SSID Umgebung könnte es aber auch so aussehen:

./wlanToggle.sh start wlan1-1 @wifi-iface[2]

Die Parameter für die gewünschte Schnittstelle lassen sich sehr einfach ermitteln. Zunächst müssen aber alle Schnittstellen einmal aktiviert werden, damit wir sie identifizieren können. Auf meinem Router habe ich zwei WLAN-Geräte. wlan0 ist für das 2,4 Ghz Band zuständig. wlan1 ist für das 5 Ghz Band zuständig. Ich habe im 2,4 Ghz Band (wlan0) genau eine WLAN-Schnittstelle und im 5 Ghz Band (wlan1) zwei WLAN-Schnitstellen.

Mit iw dev | grep Interface lassen sich alle WLAN-Geräte und Schnittstellen auflisten.

root@router:~# iw dev | grep Interface
Interface wlan0
Interface wlan1
Interface wlan1-1

Leider ist es nicht ganz ersichtlich, welches Interface nun zu welcher SSID gehört. In meinem Fall ist wlan1-1 das Gastnetz und wlan1 das private Netzwerk. Danach schauen wir in die Datei /etc/config/wireless, hier sind wifi-iface’s aufgelistet. Haben wir das richtig gefunden müssen wir abzählen an welcher Stelle es sich befindet. 0 für den ersten Eintrag eines wifi-iface’s in der Datei, 1 für den zweiten Eintrag eines wifi-iface’s und so weiter. Das Gastnetz ist bei mir an dritter Stelle und daher @wifi-iface[2].

Letztendlich müssen im Crontab noch die Einträge für das Shell-Script ergänzt bzw. ersetzt werden:

#Minuten #Stunden #Tag #Monat #Wochentag #Befehl
0 6 * * 1-5 /root/wlanToggle.sh start wlan0 @wifi-iface[0]
0 23 * * 1-5 /root/wlanToggle.sh stop wlan0 @wifi-iface[0]

Geschafft! Die WLAN-Steuerung ist jetzt intelligent und lässt sich sogar für einzelne SSID’s steuern.

Weiterführende Links: