Power over Ethernet ist eine tolle Technologie, wenn man keine Lust auf nervige Kabelei hat. Der Raspberry PI kann mit einem Modul erweitert werden sodass man den Raspberry PI POE fähig machen kann. Dabei gibt es den hauseigenen POE HAT der Raspberry Foundation oder eine gute Alternative von Waveshare.

Ich habe mich für die Waveshare-Variante entschieden, da sie einen zusätzlichen Display hat und ein paar Euro günstiger ist. Im Wiki von Waveshare zu dem POE HAT wird auch beschrieben wie dieser eingesetzt werden kann. Leider ist der Code, welcher als Beispiel zum Produkt mitkommt, in C oder Python verfügbar. Beides in meiner kleinen Tech-Blase nicht so die Wunsch-Sprachen, da ich in andere Lösungen die Steuerung mit implementieren möchte. Ich habe kurzer Hand die Befehle zur Steuerung in node.JS nachgebaut.

Mein Ziel war es den Raspberry PI zu kühlen sowie die Lautstärke zu reduzieren. So kühlt der Raspberry PI nur, wenn er zu heiß wird. Gleichzeitig kann ich Informationen auf dem Display mit ausgeben sodass ich mich nicht über SSH anmelden muss, um an den Status zu kommen.

Ziel-(Temperatur)

Mein Ziel ist es den Raspberry PI grundsätzlich um die 50C° zu halten.

Theoretische maximale Temperaturwerte sind etwa 80C° bevor der Raspberry PI anfängt mit dem Runtertakten der CPU. Ab 90-95C° kann es zu Beschädigungen kommen.

Im Leerlauf liegt der Raspberry PI etwa bei 40C° mit den kleinen Kühlkörpern und ausgeschaltetem Lüfter. Entsteht nun Last, dann soll der Lüfter (FAN) auf dem POE HAT eingeschaltet werden und den Raspberry PI 4 zusätzlich kühlen.

Um meinen Wunsch einer CPU Temperatur von um die 50C° zu halten wird der Lüfter also ab einer CPU-Betriebstemperatur von 50C° angeschaltet und bleibt solange angeschaltet bis die Temperatur wieder unter 50C° ist.

Hardware-Ausstattung

Ich nutze einen Raspberry Pi 4 mit folgendem Power Over Ethernet Modul Waveshare POE HAT for Raspberry Pi 3B+/4B.

Ich verwende zusätzlich kleine Kühlkörper für den Raspberry PI.

Darüber hinaus einen POE fähigen Switch. Hier kann so ziemlich jeder Switch verwendet werden.  

Achtung: bisschen auf die Watt-Zahl achten. Unter Last schluckt der Raspberry PI 4 etwa 7.6 Watt.

Ich habe einen professionellen managed Switch ( HP J9982A#ABB 1820-8G-PoE+ (65W) Switch-Hub ) im Einsatz mit drei POE Raspberry PIs.

Switch auf P0 stellen

Bei der Montage des Waveshare POE HAT müsst ihr den Switch auf P0 stellen, damit wir diesen später programmieren können.

Fan Switch: P0 und EN

EN für einen automatischen Start des Lüfters beim Booten des Raspberry PIs; P0, um den Lüfter programmieren zu können ohne automatischen Start.

I2C auf dem Raspberry PI aktivieren

Nachdem der Waveshare POE HAT auf dem Raspberry aufgesteckt und verschraubt wurde muss im Betriebsystem das I2C-Interface aktiviert werden.

Dafür tippen wir den folgenden Befehl ein.

raspi-config

Um das I2C-Inteface zu aktivieren wählen wir "Interface Options" in der Raspberry PI Config.

(3 Interface Options auswählen)

Als nächstes wählen wir I2C.

(P5 I2C Enable/disable automatic loading of I2C kernel module auswählen)

Wir stellen das Interface auf "Yes" also aktivieren es.

(Yes auswählen)

Es erfolgt eine Bestätigung, welche mit Ok bestätigt werden können.

(Ok auswählen)

Node.JS installieren

Bevor wir unser Script erstellen müssen eine aktuellere node.JS Version installieren. Wir installieren die aktuellste LTS (Long term support) Version mit folgendem Befehl.

sudo curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt update
sudo apt install nodejs

Nun müssen wir i2c-Module installieren, damit wir den Raspberry Pi POE HAT ansprechen können.

Wir navigieren in den Ordner wo wir unser Script ablegen wollen z.B. /home/pi/cooling

npm install i2c-bus oled-i2c-bus oled-font-5x7

Mit dem folgendem Script können wir zwei Dinge tun:

  1. Lüfter (FAN) an- und ausschalten, wenn der Wert höher ist als 50 C° (MAXHEAT)
  2. Aktuelle Temperatur und Status auf den Display schreiben.
Am POE HAT den Switch auf P0 stellen (!!!)

Dazu legen wir eine Datei im Verzeichnis an z.B. /home/pi/cooling/coolingcontrol.js

// Konfigurationswert, ab wie viel C° der Lüfter angehen soll.
const MAXHEAT = 50;

// require system modules
const spawn = require("child_process").spawn;
const os = require("os");

// require custom module
// Nicht vergessen vorher auszuführen: npm install oled-font-5x7 i2c-bus oled-i2c-bus
const font = require("oled-font-5x7");
const i2c = require("i2c-bus");
const oledI2cBus = require("oled-i2c-bus");

/**
 * piHAT-Klasse um den Waveshare POE HAT mit node.JS kontrollieren
 */
class piHAT {
    constructor() {
    }
    /**
     * Schreibt den Text auf den Display
     * @param {string} str 
     */
    writeToDisplay(str) {
        let i2cBus = i2c.openSync(1);

        let opts = {
            width: 128,
            height: 32,
            address: 0x3C
        };
        let oled = new oledI2cBus(i2cBus, opts);

        oled.setCursor(1, 1);
        oled.writeString(font, 1, str, 1, true);
        oled.update();
    }
/**
 * Holt die aktuelle Temperatur des Raspberry PIs
 */
    getTemperature() {
        return new Promise((resolve, reject) => {
            let vcgencmd = spawn("vcgencmd", ["measure_temp"]);
            vcgencmd.stdout.on("data", buff =>
                resolve(buff.toString("utf8").split("=")[1].split("'")[0])
            );
            vcgencmd.stderr.on("data", buff => reject(buff.toString("utf8")));
        });
    }
/**
 * Schaltet den Lüfter an oder aus
 * @param {boolean} shouldOn 
 */
    writeI2c(shouldOn) {
        return new Promise((resolve, reject) => {
            let wbuf = null;
            if (!shouldOn) {
                // Lüfter deaktivieren
                wbuf = Buffer.from([0x01]);
            } else {
                // Lüfter aktivieren
                wbuf = Buffer.from([0xFE]);
            }
            i2c.openPromisified(1).then(i2c1 => i2c1.i2cWrite(0x20, wbuf.length, wbuf).then(_ => { i2c1.close(); resolve(); })).catch(reject);
        });
    }
}

let hat = new piHAT();
// Aktuelle Temperatur und den Status des Lüfters auf den Display schreiben.
(async () => {
    let temp = await hat.getTemperature();
    if (temp >= MAXHEAT) {
        hat.writeI2c(true);
        console.log(`:: Hotter than expected => FAN ON ${temp} C°`);
        hat.writeToDisplay(`@${os.hostname()} (FAN: ON; ${temp})`);
    } else {
        hat.writeI2c(false);
        console.log(`:: Everything fine => FAN OFF ${temp} C°`);
        hat.writeToDisplay(`@${os.hostname()} (FAN: OFF; ${temp})`);
    }
})();

Zum Testen müsst ihr folgenden Befehl eintippen:

node coolingcontrol.js

Ich habe ein Cronjob eingerichtet, welcher alle 5-Minuten dieses Script ausführt.

Hier zu in die Console folgenden Befehl eintippen.

crontab -e

Es muss folgende Zeile hinzugefügt werden:

*/5 * * * * node /home/pi/cooling/coolingcontrol.js

Happy Cooling - Cheers Jörg!