README.md 11.4 KB
Newer Older
1
# Java und Bluetooth Low Energy auf dem Raspberry Pi
Thomas Tschol's avatar
Thomas Tschol committed
2

3
4
5
Die Intention dieses Projekts ist es, einen Startpunkt für die Entwicklung auf dem Raspberry Pi mit Java + Bluetooth LE zur Verfügung zu stellen. Es handelt
sich hierbei um einen Workshop der im Rahmen vom Proseminar "Software Engineering" angeboten wird.
Es wird gezeigt wie man alles Nötige installiert und konfiguriert als auch wie man auf dem Raspberry testet (z.B. mit Java Mockito).
6
Weiters agiert dieses Projekt auch als Bespiel wie man GitLab CI/CD in Kombination mit Java verwendet, um Testausführung und statische Codeanalyse zu automatisieren.
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

## Voraussetzungen

### Grundsätzliche Einstellungen

- `Raspberry Pi OS Lite` auf SD-Karte von Raspberry Pi geflashed
- Anmeldung mit Benutzername `pi` und Passwort `raspberry` und Änderung des Passworts mit `passwd`
- Bluetooth and WLAN sind aktiviert (weder `hard` noch `soft`-blocked)
  
      sudo rfkill list all

- Aktivierung von z.B. WiFi mit (sollte WiFi der erste Eintrag sein):

      sudo rfkill unblock 0

### Verwendung von WiFI

- Setzen des WiFi-Landes mit:

      sudo raspi-config nonint do_wifi_country AT
      sudo raspi-config nonint get_wifi_country

- Siehe: [Setting up a wireless LAN via the command line](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md)

- Überprüfung, ob man mit dem richtigen Netzwerk verbunden ist:

      iw wlan0 link

- Überprüfung, ob Internetverbindung besteht mit:

      ping google.com

### Verbindung mit Raspberry Pi

- SSH wurde aktiviert (Ausgabe soll 0 sein):
  
      sudo raspi-config nonint get_ssh

- Aktivierung von SSH mit:

      sudo raspi-config nonint do_ssh 0

- Hostname des Raspberry Pi ist bekannt:

      hostname -I

### Optional: Private/Public Key Authentifizierung

Siehe: [Passwordless SSH access](https://www.raspberrypi.org/documentation/remote-access/ssh/passwordless.md)

So vermeidet man beim Verbinden zum Raspberry Pi jedes Mal das Passwort einzugeben.

## 1) Installation

Mit Raspberry Pi verbinden:

    ssh pi@<RASPBERRY_IP_ADDRESS>

### a) Initiale Packages

Auf den neuesten Stand bringen:

    sudo apt update
    sudo apt upgrade

Essentielle Tools installieren:

    sudo apt install git
    sudo apt install cmake

### b) Maven und JDK

Installation der JDK 1.8:

    sudo apt install openjdk-8-jdk

Sicherstellen, dass tatsächlich JDK 1.8 verwendet wird:

    sudo update-alternatives --config java

Version überprüfen:

    java -version

Sicherstellen, dass sich in `usr/lib/jvm` nun `java-8-openjdk-armhf` befindet:

    sudo find / -name "java"

Editieren von `bashrc`:

    sudo nano ~/.bashrc


Es soll die Zeile `export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-armhf/` am Ende hinzugefügt werden und gespeichert werden.

Nun müssen wir das Terminal neu laden, um zu überprüfen, ob die Änderungen wirksam waren – notwendig für nächste Schritte:

    bash
    echo $JAVA_HOME

Maven installieren:

    sudo apt install maven

### c) Installation von BlueZ 5.47

Installation der Build-Tools:

    sudo apt install libglib2.0-dev libdbus-1-dev libudev-dev libical-dev libreadline-dev

Download des BlueZ Source-Codes (in geeignetem Directory):

    wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.47.tar.xz

Das tar Archiv extrahieren und in den Ordner gehen:

    tar -xf bluez-5.47.tar.xz && cd bluez-5.47

Konfigurieren des BlueZ Projekts:

    ./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var

BlueZ builden:

    make
    sudo make install

#### BlueZ Installation überprüfen

Der BlueZ Start-up Service soll nun auf das neu gebuildete BlueZ zeigen:

    cat /lib/systemd/system/bluetooth.service

Dort sollte man die Zeile `ExecStart=/usr/libexec/bluetooth/bluetoothd` vorfinden.

Ausgabe der BlueZ Version – sollte nun `5.47` sein:

    /usr/libexec/bluetooth/bluetoothd --version

#### Erlaubnis für BlueZ hinzufügen

Damit BlueZ Zugriff auf die Bluetooth-Gruppe hat, müssen wir eine eigene Erlaubnis hinzufügen. Dafür
editiert man die BlueZ DBus Konfiguration:

    sudo nano /etc/dbus-1/system.d/bluetooth.conf

Anschließend fügt man nur die Policy für die Gruppe `bluetooth` hinzu:

155
```xml
156
<busconfig>
157
158
159
160
161
162
163
  <policy user="root">
    ...
  </policy>
  <policy group="bluetooth">
    <allow send_destination="org.bluez"/>
  </policy>
  ...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
</busconfig>
```

#### Zusätzliche Konfiguration und neu starten

OpenHab User zur Bluetooth-Gruppe hinzufügen (wir benötigten zwar OpenHab nicht, aber zur Vollständigkeit):

    sudo adduser --system --no-create-home --group --disabled-login openhab
    sudo usermod -a -G bluetooth openhab

Service Definitionen neu laden:

    sudo systemctl daemon-reload

BlueZ neu starten:

    sudo systemctl restart bluetooth
   
Überprüfen, ob Bluetooth-Service aktiv ist, die richtige Version läuft (`5.47`) und es keine Fehler gibt:

    sudo systemctl status bluetooth
   
### d) Installation von tinyb

Installation der Abhängigkeiten von `tinyb`:

    sudo apt install graphviz
    sudo apt install doxygen
   
Klonen von tinyb (an geeigneter Stelle) und in den Ordner gehen:

    git clone https://github.com/intel-iot-devkit/tinyb.git && cd tinyb
   
Ordner `build` erstellen und hineingehen:

    mkdir build
    cd build
   
Builden von `tinyb` mit `cmake` (`-E` steht für experimental und stellt sicher, dass `JAVA_HOME` verwendet wird, `cmake ..` generiert das Makefile im aktuellen Verzeichnis basierend auf `CMakeLists.txt` im parent-Verzeichnis, der Prefix `/usr/` stellt sicher, dass sich die native Libraries `libjavatinyb.so` und `libtinyb.so` im Java Library Path befinden):

    sudo -E cmake -DBUILDJAVA=ON -DCMAKE_INSTALL_PREFIX=/usr ..

Ausführen von `make` und `make install`:

    sudo make
    sudo make install

## 2) Ausführen

Die Ausführung ist eher umständlich, da wir `tinyb.jar` nicht nur zur Compile-Zeit, sondern auch dynamisch zur Laufzeit laden müssen. Für diese Bluetooth-Library ist dies leider notwendig. Siehe auch: [Java* for Bluetooth® Low Energy Applications](https://web.archive.org/web/20190414051809/https:/software.intel.com/en-us/java-for-bluetooth-le-apps)

Sollten alle Befehle erfolgreich sein, dann können wir das Beispiel-Maven-Programm `bleclient` ausführen.
Dafür gehen wir in das Verzeichnis `bleclient` und führen das Programm basierend auf dem dort liegendem [README.md](bleclient/README.md) aus.

## 3) Optional: Installation z.B. auf Ubuntu 18.04/20.04

Führen Sie die Schritte `1a` und `1b` aus:

222
- Für `1b` ändert sich, dass wir statt `java-8-openjdk-armhf` die `java-8-openjdk-amd64` verwenden
223
224
225
226
227
228
229
230
231
232
233
234

Führen Sie Schritt `1c` aus:

- Sollte es bei `make` zum Fehler `error: ‘SIOCGSTAMP’ undeclared (first use in this function)` kommen, dann includen Sie `#include <linux/sockios.h>` in den nötigen Dateien z.B. `bluez-5.47/tools/rctest.c` und `bluez-5.47/tools/l2test.c`
- Dieses Problem scheint ab Ubuntu 20.04 aufzutreten. In Ubuntu 18.04 kann es sein, dass dieses Problem nicht auftritt.

Führen Sie die restlichen Schritte aus. Fertig.

Hinweis: Passen Sie beim Ausführen von Updaten/Upgrades auf. Es kann sein, dass dann Bluetooth upgegradet wird. Dies wollen wir vermeiden. Wir wollen maximal Version `5.47` verwenden.

## Fragen und Antworten

235
236
237
238
239
240
### Wie kann ich GitLab CI/CD auf mein eigenes Projekt anwenden?

- Dafür muss man in [gitlab-ci/MakeFile](gitlab-ci/Makefile) das Target Repository auf das eigene ändern, das Image builden und pushen. In `Packages` -> `Container Registry` kann man sehen, ob das Docker Image tatsächlich gepushed wurde.
- Weiters muss das Base-Image in [.gitlab-ci.yml](.gitlab-ci.yml) auf das eigene Image zeigen.
- Damit das Jacoco-Coverage Badge funktioniert muss man in die Einstellungen gehen und für das eigene Projekt eine Badge hinzufügen. Diesbezüglich gilt es sicherzustellen, dass die `Badge Image URL` korrekt ist d.h. die URL muss auf das eigene Repository zeigen und auf das `.svg`-Bild, welches von der GitLab Pipeline beim `bleclient-test`-Job generiert wurde.

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
### Was mache ich, wenn irgendetwas in der Installation schief läuft?

- Sicherstellen, dass alle Befehle richtig ausgeführt wurden.
- Generell kann es helfen, noch einmal alle Befehle von vorne auszuführen.

### Was wenn der der Java BluetoothManager eine Exception wirf (z.B. NullPointerException)?

- Sicherstellen, dass das gebuildete `tinyb.jar`zur Verfügung steht
- `tinyb.jar` muss zur Laufzeit als Parameter übergeben werden z.B. `–cp target/<JAR_FILE>:./lib/tinyb.jar:./target/dependencies/*`

### Was wenn ich beim Ausführen ein Problem mit der nativen API Version bekomme?

- Wahrscheinlich wurde die `tinyb.jar` nicht korrekt zur Laufzeit geladen
- Sicherstellen, dass sie richtig geladen wird z.B. `–cp target/<JAR_FILE>:./lib/tinyb.jar:./target/dependencies/*`

### Wieso kann ich das Programm nicht mit -jar ausführen?

- Entweder man verwendet `-cp` für Classpath oder `-jar`, aber nicht beides
- Für `-jar` benötigt man weiters auch noch eine Manifest-Datei (diese müsste man in Bezug auf das `tinyb.jar` auch konfigurieren)

### Wieso können die native Libraries nicht gefunden werden?

- Sollte grundsätzlich kein Problem sein, wenn man der Anleitung gefolgt hat
- Durch `-DCMAKE_INSTALL_PREFIX=/usr` sollten diese korrekt gesetzt sein
- Siehe auch bei Installation `tinyb/build/install_manifest.txt`
- Mit `java -cp` korrekt ausführen und nicht mit `-jar`
- Wenn es immer noch nicht möglich ist, dann muss man wirklich sicherstellen, dass sich `libjavatinyb.so` und `libtinyb.so` tatsächlich im Java Library Path befinden.
    - Prinzipiell könnte man diese Dateien `tinyb/build/java/jni/libjavatinyb.so` und `tinyb/build/src/libtinby.so` auch direkt nach `/usr/lib` kopieren

### Wieso bekomme ich eine BluetoothException mit Timeout was reached?

- Sicherstellen, dass sich der TimeFlip tatsächlich in Reichweite befindet
- Sicherstellen, dass die Batterie richtig im TimeFlip ist

### Wieso bekomme ich Exceptions beim Auslesen von Charakteristiken?

- Sicherstellen, dass das Passwort richtig vorher an den TimeFlip geschrieben wurde, dann sollte man alle Charakteristiken auslesen können
- Es kann sein, dass man versehentlich das Passwort über die TimeFlip App gesetzt hat. Wenn man die Batterie kurz herausnimmt und noch einmal einsetzt, dann sollte das Passwort zurückgesetzt sein.

### Was mache ich, wenn das bleclient Programm keinen TimeFlip ausgibt?

- Sicherstellen, dass der TimeFlip eingeschalten ist (z.B. Überprüfung mit Handy-App wie `nRF Connect`)
283
    - Am besten notiert man sich die Bluetooth Addresse des TimeFlips
284
285
286
287
288
289
290
291
292
293
294
295
- Sicherstellen, dass der TimeFlip mit keinem anderen Gerät gekoppelt ist
    - Entkoppeln von Bluetooth, TimeFlip App, etc.
- Theoretisch ist es möglich, dass aus irgendeinem Grund das Passwort auf dem TimeFlip z.B. mit der TimeFlip App gesetzt wurde. In diesem Fall sollte man die Batterie kurz entfernen und wieder reinstecken


## Links
* [Raspberry Pi Bluetooth Manager TinyB - Building bluez 5.47 from sources](https://github.com/sputnikdev/bluetooth-manager-tinyb)
* [TinyB Bluetooth LE Library](https://github.com/intel-iot-devkit/tinyb)
* [Raspberry Pi Installation of TinyB (Note: do not install bluez)](http://www.martinnaughton.com/2017/07/install-intel-tinyb-java-bluetooth.html)
* [Java for Bluetooth LE applications](https://www.codeproject.com/Articles/1086361/Java-for-Bluetooth-LE-applications)
* [TinyB Java examples (HelloTinyB.java, etc.)](https://github.com/intel-iot-devkit/tinyb/tree/master/examples/java)
* [Non-interactive raspi-config interface](https://github.com/raspberrypi-ui/rc_gui/blob/master/src/rc_gui.c#L23-L70)