Raspberry PI als SignalK-Server einrichten

Als zentraler Server im SignalK-Netzwerk dient ein Raspberry PI. In diesem Schritt wird beschrieben, wie der Raspberry PI dafür konfiguriert und getestet wird. Dafür installieren wir den SignalK-Server aus den Quellen und konfigurieren den Raspberry PI als WLAN-Access-Point, damit wir ein privates, nicht mit dem Internet verbundenes WLAN haben, in dem wir unsere WLAN-Clients einbinden können.

Verwendete Hardware und Software

  • PC mit Debian 10.0
  • Raspberry PI 3 Model B V 1.2
  • Raspbian Buster Lite (02.12.2020)

SD-Karte erstellen unter Linux

Raspbi OS könnt ihr von der offiziellen Download-Seite herunterladen. In dieser Anleitung wird das Raspi OS Lite Image vom 02.12.2020 verwendet, mit anderen Images aus dem „Buster“-Release sollte es aber auch funtionieren. Nach dem herunterladen das Image entpacken:

ralph@debian:~/Downloads$ unzip 2020-12-02-raspios-buster-armhf-lite.zip 
Archive:  2020-12-02-raspios-buster-armhf-lite.zip
  inflating: 2020-12-02-raspios-buster-armhf-lite.img 

Bevor ihr das Image auf die SD-Karte schreiben könnt, müsst ihr herausfinden, welches Device für die SD-Karte verwendet wird. Dafür könnt ihr den Befehl „dmesg“ direkt nach dem einlegen der SD-Karte benutzen. Üblicherweise erzeugt der Befehl sehr viele Ausgaben, mit der Pipe „|“ zu dem Kommando „tail“ werden nur die letzten Zeilen angezeigt:

ralph@debian:~/Downloads$ sudo dmesg | tail
...
[ 2331.527848] mmc0: new SDHC card at address 1234
[ 2331.528287] mmcblk0: mmc0:1234 SA32G 28.9 GiB 
[ 2331.530239]  mmcblk0: p1 p2

In unserem Fall sind die letzten drei Zeilen relevant, die aussagen, dass eine SD-Karte mit zwei Partitionan (mmcblk0: p1 p2) als Block-Device /dev/mmcblk0 erkannt wurde. Die Anzahl der Partitionen hängt von der vorherigen Verwendung der SD-Karte ab und ist für uns irrelevant. Wir schreiben einfach das Image mit dem Befehl „dd“ auf die SD-Karte:

ralph@debian:~/Downloads$ sudo dd if=2020-12-02-raspios-buster-armhf-lite.img of=/dev/mmcblk0
3629056+0 Datensätze ein
3629056+0 Datensätze aus
1858076672 bytes (1,9 GB, 1,7 GiB) copied, 597,741 s, 3,1 MB/s

Nach dem Schreiben des Images muss noch ssh aktiviert werden. Wenn ihr den Raspberry PI „headless“ benutzt (ohne Tastatur und Display, wie für Server üblich) muss das vor dem Booten geschehen. Dafür müsst ihr eine leere Datei mit dem Namen „SSH“ auf der Boot-Partition anlegen. Die Boot-Partition ist die erste Partition (die dmesg-Ausgabe oben war von einem alten Raspbian). Diese muss in ein Verzeichnis gemounted werden, bevor darauf zugegriffen werden kann. Anschliessend kann mit dem Befehl „echo“ und einer Ausgabeumleitung „>“ erstellt werden:

ralph@debian:~$ mkdir tmp
ralph@debian:~$ sudo mount /dev/mmcblk0p1 ./tmp/
ralph@debian:~$ sudo sh -c 'echo "" > ./tmp/SSH'
ralph@debian:~$ sudo umount ./tmp

Bei neueren raspbian-Versionen gibt es zudem den Default-User „pi“ nicht mehr, statt dessen werdet ihr beim ersten Start aufgefordert, einen User anzulegen. Da das bei einem „headless“-System nicht funktioniert, müsst ihr zusätzlich eine Datei „userconf.txt“ auf der Boot-Partition anlegen. Diese enthält einen Eintrag „username:password“, wobei das Passwort eine verschlüsselte Version ist, die z.B. mit openssl erzeugt werden kann. Am besten erzeugt ihr erst das Passwort:

ralph@debian:~$ echo 'mypassword' | openssl passwd -6 -stdin
$6$Es5sx3K50UW4.yXj$z9cOhEAK24tJ2w0JbGWf1SQXddvVjNu0X/QqFDgKfLw7wqOAJuO9RL54VYNMr8sztcuhfkJEmTfQYBpHv9SvP.

Das ausgegebene Passwort könnt ihr mittels „Kopieren“ (In einer Linux-Konsole strg-shift-c, unter Windows per Menü im Terminal-Programm) in die Zwischenablage kopieren. Als nächstes mit „nano“ die Datei anlegen:

ralph@debian:~$ nano ./tmp/userconf.txt

Mit dem user „testuser“ und dem Passwort von oben sieht die Datei damit wie folgt aus:

testuser:$6$Es5sx3K50UW4.yXj$z9cOhEAK24tJ2w0JbGWf1SQXddvVjNu0X/QqFDgKfLw7wqOAJuO9RL54VYNMr8sztcuhfkJEmTfQYBpHv9SvP.

Anschließend könnt ihr die Partition mit „umount“ unmounten.

Grundinstallation auf dem Raspberry Pi

Nachdem der Raspberry Pi gebootet worden ist, können wir uns an die Installation der ersten Pakete machen. Standardmäßig meldet er sich als „raspberrypi“ beim Router an. Als erstes loggen wir uns ein (das Standards-Passwort ist „raspberry“), setzen ein neues Password und updaten das System:

ralph@debian:~$ ssh pi@raspberrypi
The authenticity of host 'raspberrypi (2001:16b8:307b:9700:b14e:6b35:1841:5839)' can't be established.
ECDSA key fingerprint is SHA256:e8XuEC/4QOPTWy1n/16etgRGFVJbkvPss8Wrq4z6Z1A.
Are you sure you want to continue connecting (yes/no)? yes
...
pi@raspberrypi:~ $ passwd
Changing password for pi.
Current password: 
New password: 
Retype new password: 
passwd: password updated successfully
pi@raspberrypi:~ $ sudo apt-get update
Get:1 http://archive.raspberrypi.org/debian buster InRelease [32.6 kB]
...
pi@raspberrypi:~ $ sudo apt-get upgrade
Reading package lists... Done
...
Do you want to continue? [Y/n] y
...
pi@raspberrypi:~ $ sudo apt-get dist-upgrade
Reading package lists... Done
...
pi@raspberrypi:~ $ sudo reboot
Connection to raspberrypi closed by remote host.
Connection to raspberrypi closed.

Bei dem Reboot wird die SSH-Verbindung getrennt, danach müsst ihr euch neu einloggen. Anschließend installieren wir die benötigten Abhängigkeiten für den SignalK-Server. Bei node.js/npm gibt es eine kleine Besonderheit: Die aktuelle Version npm/nodejs installiert man mit npm, das auf node.js basiert… Daher installieren wir zunächst die alte, in der Distribution enthaltene Version, mit der wir dann das Update auf die neue Version durchführen. Da die Installationen in verschiedene Pfade erfolgen, sind dabei keine Konflikte zu befürchten. Wir müssen nur sicherstellen, dass anschließend die neue Version von der Bash verwendet wird. Zuerst wieder auf dem Raspberry Pi anmelden und die in der Distribution enthaltenen Pakete installieren:

ralph@debian:~$ ssh pi@raspberrypi
pi@raspberrypi's password:
...
pi@raspberrypi:~ $ sudo apt-get install git ntp netcat nodejs npm libavahi-compat-libdnssd-dev ntpstat
Reading package lists... Done
...
After this operation, 91.7 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
...

Als nächstes führen wir das Update von npm durch und bringen die bash mit „hash“ dazu, sich den neuen Pfad für „npm“ zu merken, damit die upgegradete Version von npm verwendet wird. Dieses Kommando kann fehlschlagen, falls die bash sich noch keinen Pfad für „npm“ gemerkt hat. Mit „npm -v“ lässt sich überprüfen, ob für user und root die neue Version von npm verwendet wird:

pi@raspberrypi:~ $ sudo npm install npm -g
...
pi@raspberrypi:~ $ hash -d npm
pi@raspberrypi:~ $ sudo npm -v
6.14.10
pi@raspberrypi:~ $ npm -v
6.14.10

Als nächstes können wir das Tool „n“ und damit die aktuelle (stable) Version von node.js installieren. Auch für „node“ muss die bash sich wieder den neuen Pfad merken:

pi@raspberrypi:~ $ sudo npm install -g n
/usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n
+ n@7.0.0
added 1 package from 4 contributors in 1.484s
pi@raspberrypi:~ $ sudo n stable
  installing : node-v14.15.3
...
pi@raspberrypi:~ $ hash -d node
pi@raspberrypi:~ $ node -v
v14.15.3

Installation und Test des SignalK-Servers

Nachdem wir das aktuelle node.js haben, kann der SignalK-Server installiert werden. Damit wir die neuste Version bekommen, installieren wir ihn direkt aus dem github-Repository. Dafür klonen wir dieses Repository, updaten/installieren dann die Abhängigkeiten mit npm und starten ein build:

pi@raspberrypi:~ $ git clone https://github.com/SignalK/signalk-server-node.git
Cloning into 'signalk-server-node'...
...
pi@raspberrypi:~ $ cd signalk-server-node/
pi@raspberrypi:~/signalk-server-node $ npm update
...
pi@raspberrypi:~/signalk-server-node $ npm install
...
pi@raspberrypi:~/signalk-server-node $ npm run build

Jetzt ist der SignalK-Server gebaut und wir können ihn für den ersten Test starten, bei dem eine Messung abgespielt wird:

pi@raspberrypi:~/signalk-server-node $ ./bin/nmea-from-file

Wenn ihr jetzt auf dem PC einen Webbrowser öffnet und dort die URL: „http://raspberrypi:3000“ eingebt, sollte sich das „SignalK Dashboard“ öffnen:

SignalK Server Dashborad

Wenn ihr jetzt unter „Webapps“ die App „@Signalk/Instrumentpanel“ öffnet, solltet ihr die folgende Visualisierung der SignalK-Daten sehen:

@Signalk/Instrumentpanel

Wenn soweit alles funktioniert, seid ihr für den nächsten Schritt vorbereitet. In diesem werden wir Daten mit Sensoren an einem Arduino messen, an den SignalK-Server senden und in dem Instrumentpanel anzeigen.

Einrichten des WLan-Access-Points

Als nächstes richten wir den WLan-Access-Point ein, damit wir ein privates WLan haben, dass wir für eine Verbindung mit einem ESP8266 oder ESP32 verwenden können. Der hier beschriebene Weg lehnt sich an die offizielle Dokumentation der Raspberry PI Foundation an, wir fassen hier aber kurz die für uns wichtigsten Schritte zusammen. Falls ihr mehr Informationen zu einem der Schritte braucht, schaut am besten in der offiziellen Dokumentation nach. Das Routing zwischen beiden Netzen aktivieren wir hier nicht. Als erstes installieren wir die benötigten Pakete:

pi@raspberrypi:~ $ sudo apt-get install hostapd dnsmasq
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
.
.
.
After this operation, 2,666 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
.
.
.

Anschließend aktivieren wir den hostapd:

pi@raspberrypi:~ $ sudo systemctl unmask hostapd
Removed /etc/systemd/system/hostapd.service.
pi@raspberrypi:~ $ sudo systemctl enable hostapd
Synchronizing state of hostapd.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable hostapd

Anschließend müssen wir für das wlan0-Interface das Raspberry Pi eine statische IP-Konfiguration anlegen. Wir verwenden hier das Netzwerk 192.168.4.0/24 für das WLan und geben dem Raspberry Pi die erste freie Adresse dort. Dafür öffnen wir die Datei /etc/dhcpd mit einem Texteditor:

pi@raspberrypi:~ $ sudo nano /etc/dhcpcd.conf

Und fügen am Ende folgende Zeilen hinzu. Ihr könnt diese im Browser markieren, mit Strg+c kopieren und dann mit Strg+Shift+v in dem Texteditor auf dem Raspberry Pi einfügen:

interface wlan0
    static ip_address=192.168.4.1/24
    nohook wpa_supplicant

Als nächstes erstellen wir eine Konfiguration für dnsmasq, der DHCP und DNS für das WLan übernimmt. Die originale Konfigurationsdatei können wir für verschieben:

pi@raspberrypi:~ $ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
pi@raspberrypi:~ $ sudo nano /etc/dnsmasq.conf

In die neue Konfigurationsdatei fügen wir folgenden Inhalt ein:

interface=wlan0 # Listening interface
dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
                # Pool of IP addresses served via DHCP
domain=wlan     # Local wireless DNS domain
address=/signalk.wlan/192.168.4.1
                # Alias for this router

Falls das WLan noch nicht verwendet wurde – was der Fall ist, wenn ihr dieser Dokumentation gefolgt seit – ist es per „rfkill“ deaktiviert, da für die verwendbaren Frequenzen das Land bekannt sein muss, in dem das WLan aktiviert wird. Dazu öffnen wir die Datei /etc/wpa_supplicant/wpa_supplicant.conf:

pi@raspberrypi:~ $ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf 

Und fügen als letzte Zeile den „Country Code“ hinzu. Für Deutschland sieht die Datei dann wie folgt aus:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=DE

Danach kann „rfkill“ deaktiviert werden:

pi@raspberrypi:~ $ sudo rfkill unblock wlan

Abschließen erstellen wir die Konfiguration für hostapd. In der hier gezeigten Konfiguration wird als Netzwerkname (ssid) „SignalkWlan“ und als Passwort „SignalkWlan!Pwd“ verwendet. Wir werden beides in den Beispielen durchgehend verwenden. Ihr solltet es natürlich es bei euch natürlich ändern! Der „Country Code“ wird auf Deutschland eingestellt. Wir legen die Konfigurationsdatei mit einem Texteditor an:

pi@raspberrypi:~ $ sudo nano /etc/hostapd/hostapd.conf

Und fügen folgenden Inhalt in die Datei ein:

country_code=DE
interface=wlan0  
ssid=SignalkWlan  
hw_mode=g
channel=7    
macaddr_acl=0
auth_algs=1  
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=SignalkWlan!Pwd       
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

Nachdem ihr den Raspi mit:

pi@raspberrypi:~ $ sudo reboot

neu gestartet habt, solltet ihr euch mit dem neuen WLan verbinden können. Anschließend könnt ihr euch mit SSH verbinden, um den SignalK-Server zu starten:

ralph@debian:~$ ssh pi@192.168.4.1
The authenticity of host '192.168.4.1 (192.168.4.1)' can't be established.
ECDSA key fingerprint is SHA256:e8XuEC/4QOPTWy1n/16etgRGFVJbkvPss8Wrq4z6Z1A.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.4.1' (ECDSA) to the list of known hosts.
pi@192.168.4.1's password:
Linux raspberrypi 5.4.79-v7+ #1373 SMP Mon Nov 23 13:22:33 GMT 2020 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Feb  9 21:13:41 2021 from 2001:16b8:30bb:2500:4f76:711f:ad79:4351
pi@raspberrypi:~ $ cd signalk-server-node/
pi@raspberrypi:~/signalk-server-node $ ./bin/nmea-from-file

Wenn ihr jetzt einen Webbrowser öffnet und dort die Adresse „http://192.168.4.1:3000“ eingebt, sollte sich dort wieder das SignalK-Server-Dashboard öffnen. Geschafft – der SignalK-Server ist jetzt auch über WLan erreichbar!

Ergebnisse und nächste Schritte

Wir haben jetzt einen aktuellen SignalK-Server auf einem Raspberry PI eingerichtet und getestet. Was uns noch fehlt, sind ein paar echte Eingangssignale. Die soll im nächsten Schritt ein Arduino Uno erzeugen. Während der weiteren Entwicklung werden wir die Installation des Raspberry Pi um weitere Dienste ergänzen müssen. Wir werden diese Seite dann Schritt für Schritt ergänzen und euch im Blog auf Stand halten!