Delporte F. Getting Started With Java On The Raspberry Pi 2020
Delporte F. Getting Started With Java On The Raspberry Pi 2020
Frank Delporte
This book is for sale at http://leanpub.com/gettingstartedwithjavaontheraspberrypi
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Chapter 1: Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Content overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
About me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Sources and scripts used in this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Where to find them . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Get the sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
The styling used in the book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Read the README! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
What’s next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Thanks to… . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Using streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
What’s next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Interview with Jakob Jenkov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
FXRibbon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
ControlsFX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
PickerFX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Interview with Gerrit Grunwald . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Minimal JavaFX 11 sample application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Add new archetypes to Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Creating an empty application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Running the empty application from Visual Studio Code . . . . . . . . . . . . . . . . . . 130
Running the application on the Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Example 1: TilesFX dashboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Wiring and testing in terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Blink an LED with Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Building our first JavaFX application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Run the application on PC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Run the application on the Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Start a Java application when the Pi starts up . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Disable screensaver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Example 2: Interact with an I²C relay board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Enable and test I²C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Coding the I²C controller application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Running the relay controller on the Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Example 3: Build a UI with FXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Generate an empty FXML project as a starting point . . . . . . . . . . . . . . . . . . . . 164
Scene Builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
Chapter 1: Introduction
Welcome! Whether you are a newbie in Java, and want to learn from examples, or know the
language, and want to get started with electronics and a Raspberry Pi, I hope you will find valuable
new information in here!
This is not a book to learn every aspect of the Java language. There are already a lot of those written
by way better programmers than me, so please check your bookstore or an online course if you
want to get a real deep knowledge of the Java programming language. My goal was to bundle a lot
of sample code and information, I collected while learning and experimenting, and to get anyone
interested in Java to take a quick start by using the examples to set up their own experiments.
By following these examples, you will also learn the language bit by bit.
Over the last couple of years, I focused on Java in my professional job. But on the other hand, I also
got involved in CoderDojo (coding club for children) where I first was able to make a blinking LED
with some simple code on Arduino and a Pi.
If I see how kids learn to work with electronics and programming at CoderDojo, I’m jealous those
things didn’t exist when I was a kid. Yes, I managed to control a relay-board with my Commodore 64
but it took me years to collect all needed knowledge and components to reach that goal. Now thanks
to online shopping and knowledge sharing that same result can be achieved in days or hours…
As a professional Java-developer with a love for open-source, I set myself as a personal goal for 2019
to run a recent Java version (Java 11 or newer) on the Pi, with a JavaFX user interface, and control
an LED with it. Very basic I know, but it resulted in a series of blog posts about each step to reach
this goal. Based on these blog posts, I also wrote an article for MagPi (in the Dutch and French July
2019 edition) and produced an Udemy course¹.
And as a blinking LED is the equivalent of a “Hello World” program, I continued with
experimenting and ended up with… this getting started book! A whole list of easy “recipes” to get
you started with many different Java libraries and electronics to build your projects. Take one or
more of these “recipes”, combine and mix them to your taste, experiment and explore!
Oh, and this is not an anti-Python or anti-C book! Java is the language I love and use the most, but
for every problem you need to select the best solution. And in some cases, this could be Java or
something else…
¹https://www.udemy.com/course/use-java-11-and-java-fx-11-on-a-raspberry-pi
Chapter 1: Introduction 2
Content overview
You can read this book from start to end, but can also use it as a “cookbook” and select the topics of
your interest. For instance, you don’t need to know the history of Java to work with it, but it’s here
for your reference.
In between some of the chapters you find a short “Just a thought”-piece about the things I find
important and I would like to share with you. I’m also very happy I could interview some of my
heroes, included in the chapters they are related to.
Chapter 1: Introduction: On the next pages you can find more info about the sources used in this
book and are available for free online, and some additional info about readme-files and a thank-
you-list.
Chapter 2: Tools and hardware used in this book: Setup a Raspberry Pi with Raspbian and an
overview of the software used on both Pi and PC. Also generic info about some of the most-used
hardware components in this book.
Chapter 3: Choosing an IDE: Info about IntelliJ IDEA and Visual Studio Code.
Chapter 4: About Java: History of Java, different versions and tools within the eco-system and how
to install it on your Pi and PC. And of-course a crash course so you get a grasp of the language if
it’s completely new to you.
Chapter 5: Raspberry Pi pinning: Different types of Raspberry Pi-boards and the different headers,
pins and pin types and how you can use them to connect different types of hardware.
Chapter 6: What is Maven?: More info on Maven, the tool we will use to test, build and run our
Java projects on PC and Pi.
Chapter 7: About JavaFX: The visual Java framework we will use to build beautiful user interfaces
to interact with our Pi and hardware.
Chapter 8: Bits and bytes: The magic of ones and zeros and how they are combined into longer
values.
Chapter 9: PI4J: A framework that makes it easier to work with the GPIOs from Java with multiple
hardware examples.
Chapter 10: Spring: Building a Java application which exposes our Pi as a web service to store data
or control the GPIOs.
Chapter 11: Message Queues: Use your Pi as a message handler to receive and send messages to
different devices like other Pi’s, PCs or Arduino’s.
Chapter 1: Introduction 3
About me
I’m Frank Delporte (@FrankDelporte² on Twitter, °1973) who started programming at age 11 when
I got a Commodore 64. With Basic as the programming language, some magnetic switches, and
a relay board, I managed to control my Lego train. After studying at a film school, I started my
professional career as a video editor, but quickly got involved in the first multimedia and online
video projects in Belgium. Combining my interest in multimedia and programming, this resulted in
a journey through C#, Flash, HTML/JavaScript, Flex, SQL, Qt, Java…
Currently, I work as a technical lead and software developer at Televic Rail in Belgium with a team
of highly skilled hard- and software-engineers. We are building the next generation of Passenger
Information Systems used onboard rail vehicles to inform the passengers in the best possible way
so they are fully informed about their journey. Making a bridge between on- and off-board data
sources empower us to combine information into nice looking and easy to read screens.
I always try to “get things moving and done” while trying to stick to the KISS principle (see
“Important abbreviations”).
As the best way to learn is teaching, I was one of the first lead coaches of CoderDojo in Belgium
and started two Dojo’s (Roeselare and Ieper) where I first came into contact with Arduino, Pi and
all those other amazing tools, all thanks to the inspiring colleague-coaches.
On my blog webtechie.be³, some projects are shared, which resulted in an article for MagPi which
was the starting point for this book.
I live together with my wife Conny and son Vik in Passendale (Belgium), a small town that was one
of the main battlegrounds of WWI.
²https://twitter.com/FrankDelporte
³https://www.webtechie.be
Chapter 1: Introduction 4
On the other hand, if you know how to checkout code, please do! It will give you a copy of all
the code and scripts but also allow you to make changes and improvements and send them as pull
requests if you know how to work with git. It would be great if the samples could be further
improved by you! I’m looking forward to your pull request.
Here is how you check out the code into your home directory on the Pi:
⁴https://github.com/FDelporte/JavaOnRaspberryPi
⁵https://github.com/FDelporte/JavaOnRaspberryPi/blob/master/CHANGES.md
Chapter 1: Introduction 5
1 $ cd /home/pi
2 $ mkdir Book
3 $ cd Book
4 $ git clone https://github.com/FDelporte/JavaOnRaspberryPi.git
Inside most of the projects, you’ll find a “target” directory with the jar-file which you can run directly
if you don’t want to modify the code and/or build the project yourself. More info on building and
running later in this book…
Chapter 1: Introduction 6
Command and script examples have the same styling, and when the line starts with a “$” that means
it is a command you must type in in the terminal, the following lines are the output you will get,
for example, for the command “java -version”:
1 $ java -version
2 openjdk 11-BellSoft 2018-09-25
3 OpenJDK Runtime Environment (build 11-BellSoft+0)
4 OpenJDK Server VM (build 11-BellSoft+0, mixed mode)
All references to the sources in the GitHub project will look like this, referring to the subdirectory
in the GitHub project⁶:
https://github.com/FDelporte/JavaOnRaspberryPi
Chapter_01_Introduction > README.md
⁶https://github.com/FDelporte/JavaOnRaspberryPi
Chapter 1: Introduction 7
Guidelines
A README uses a list of conventions for the formatting, the ones used most in this book:
Example
This is a short example file:
When you look at this file online it will look like this:
Chapter 1: Introduction 8
What’s next?
In the source files you can find an overview of links with interesting articles on how and why to
write a good README:
Thanks to…
…all open-source contributors and bloggers who are constantly pushing Java, JavaFX, Pi4J and
all those other marvelous tools, frameworks, libraries forward. Without them, we wouldn’t be able
to produce such easy to build and good-looking applications! Only a limited list is mentioned in this
book, but there are a lot more and they are constantly sharing their work and knowledge on the
internet. Keep an eye out for them!
…my colleagues who are always critical when doing pull requests and sharing their knowledge. I
fully agree with the phrase “What one developer can do in one month, can be done by two developers
in two months”, but two experienced and critical developers will produce better code, than a solo
player.
Read the book “The Mythical Man-Month” by Fred Brooks⁷ if you want to know why a late
software project becomes even later when adding manpower.
Or even better, buy two copies of this book for your manager, so he can read it twice as fast
;-)
…Elektor who triggered me to start writing this book and publish it as a real paper book! A true
bucket list thing achieved now.
…my wife and son, who I have neglected too much the last months. I promised them that would
change once this book was finished. It’s a pity they know me too well and immediately asked what
my next project would be :-)
…the reviewers, interviewees and everyone who helped me to realize this book!
Reviews, contributions, tips, feedback, ideas… by Stijn Deroo, Nathalie Delporte, Lieven Baes,
Trisha Gee, Vlad Mihalcea, Kasper Zutterman, Ludo Joris, Jan Lamote, Kim Harding, Catherine
Van Damme, Chris Van Bael, Mark Heckler, Pieterjan Deconinck, Kasia Pranke, Marian Faydula,
Wouter Vanhauwaert, Michael Egger and… you? Please send me your feedback via e-mail on
javaonraspberrypi@webtechie.be! You can also send me pull-requests on GitHub if you want to
contribute to the examples.
Legal stuff
Raspberry Pi and the associated logo are trademarks of The Raspberry Pi Foundation. The
name and logo used throughout this book and their trademarked status are acknowledged
here.
Oracle and Java are registered trademarks of Oracle and/or its affiliates.
Other names may be trademarks of their respective owners.
⁷https://en.wikipedia.org/wiki/The_Mythical_Man-Month
Chapter 2: Tools and hardware used
in this book
In the past, most good tools were expensive and as such, used by a limited user group. But thanks to
open source soft- and hardware, and freeware developers, you can now build awesome stuff without
the need to kill your wallet.
You will find many of these in this book. Are these the best? Are these the only ones to be used? No,
definitely not! But they are what I have used and considered to be “good enough for the job” and
easy to use, which is the goal of this book.
Chapter 2: Tools and hardware used in this book 11
Raspberry Pi
Just when I started working on this book, the 4th edition of the Pi became available. Combined
with a 4K display this turned out to be a perfect companion while testing and building stuff. It’s not
required, but maybe it’s a good idea to buy a fan as the board can become pretty hot. But WOW,
what a magnificent device! Most of the writing and coding for this book was done on a Pi 4! And this
was also the first time I used a 4K display, another WOW! Two code windows open on one single
screen, each using less than half of that screen, and still space for some other tools like a terminal
window.
As you always risk “burning” a GPIO pin during experiments, most of the experiments were done
on some older - cheaper - Pi 3 boards.
Keep in mind, you can use the same SD card with Raspbian and Java JDK on different Pi’s (except
the oldest ones with an ARMv6 processor, see “Chapter 4: Java” > “Install Java on a Pi”). When you
have a working SD card with all the applications you need, you can take it out from a Pi 4 and use
it with a Pi 3 board or vice-versa.
Prepare the Pi
Operating system on SD
When you start with a new Pi, you will need to prepare an SD card with the operating system. You
can download this from the Raspberry Pi site by selecting “Raspbian with desktop and recommended
software” from the downloads page⁸.
⁸https://www.raspberrypi.org/downloads/raspbian/
Chapter 2: Tools and hardware used in this book 12
Select the ZIP and wait until the download has finished. In the meantime, you can also download a
tool to “burn” this file to the SD card. On PC I prefer to use Rufus⁹, which you can download in a
portable version and run without the need to install anything.
On Linux you don’t need to install additional software to burn the downloaded OS to an SD
card but can use the “dd” command in the terminal.
Make sure you select the correct location to write to, by following this step-by-step tutorial
on the Raspberry Pi website¹⁰.
The current Raspbian OS with desktop and recommended software, needs around 7GB. If you use
a micro SD card of 8GB, only 1GB is left, which is not enough space to experiment with Java and
applications… So it’s recommended to use a card of 16GB or more. You will also need an adaptor
to use the micro SD in most SD slots of a PC. So we put the small SD in the adapter to write the
operating system on it on a PC.
⁹https://rufus.ie/
¹⁰https://www.raspberrypi.org/documentation/installation/installing-images/linux.md
Chapter 2: Tools and hardware used in this book 13
Run Rufus and select the “Device” (make sure to select the SD card and not the hard drive of your
PC!!!) and the downloaded ZIP file with Raspbian as “Boot selection”.
You can leave the default settings for the other inputs, and click “START”, after which you have to
confirm.
This is your last chance to make sure you selected the correct device! After clicking “OK” the Status
bar will show the progress, wait until “READY” appears.
Chapter 2: Tools and hardware used in this book 14
You can now remove the SD card from the PC and put the small card in the Pi. Watch out for the
orientation, don’t push too hard because that means you didn’t correctly insert the card.
Now start your Pi and you will soon get your desktop view. Click around a bit to check the pre-
installed programs. You can also configure the WiFi connection to connect it to your local network.
Don’t just unplug the power, but turn off in Raspbian. Otherwise, you might get a corrupted
SD card! This topic is discussed in detail on StackExchange¹¹.
When you start the Pi for the first time with a new SD card, the root partition will be resized
automatically to use the maximum available capacity. If you need to do this manually, you can
use “raspi-config” which provides a lot of configuration and maintenance options. Start it from the
terminal on your Pi:
1 $ sudo raspi-config
To make sure you are using the latest version of this tool, start by selecting option “8 Update”. The
tool will restart and now choose option “7 Advanced options”.
¹¹https://raspberrypi.stackexchange.com/questions/381/how-do-i-turn-off-my-raspberry-pi
Chapter 2: Tools and hardware used in this book 15
In this advanced screen, select the first option “A1 Expand Filesystem”. Your Pi will need to restart
and then you can check the disk usage with the following command in the terminal:
1 $ df -h
The disk is split into multiple partitions, but the biggest part is used by the root partition where
all programs, our files… are stored. In my case, using a 32GB card, the root partition is 29GB with
around 22GB free space left.
This T-shaped board can be plugged in directly in a breadboard and you can easily read the pinning
numbers from it. The T-board is an identical copy of the connector on the Pi. The drawback is the
Chapter 2: Tools and hardware used in this book 16
big cable which takes a lot of space. You can find a lot of different ones online, for example, on ebay
when searching for “raspberry pi t-shaped”.
Breadboard Pi Bridge
For this board¹² you have to nicely align the Pi and the breadboard before you push it down, trying
not to bend the pins (been there, done that…). If you follow the online video manual¹³, you will get
a nice clean result and the GPIO pinning numbers will now end up in numerical order!
Without the flat cable, it is much more compact and my preferred solution. And the additional cover
on the Pi avoids damaging it.
Pi bridge board
needed while keeping everything nicely organized. The orange wireless keyboard was part of a
Kano kit¹⁴ with a much older Pi, which can not run Java.
1 rm --help
In the following “[path]” refers to a relative or absolute path. An absolute path starts with “/”, e.g.
1 /home/pi
Please note that the table below is not exhaustive and your favorite commands may be missing. Some
of these commands are only available on Debian-based Linux systems like Raspbian for Raspberry
Pi.
Command Description
pwd Display the name of the current working directory.
ls List the content of the current directory.
ls [path] List the content of the specified directory.
ls -l List the content of the current directory with additional
information.
ls -a List all files including hidden files beginning with ‘.’ (i.e.
dotfiles).
ls -h List all files and display the file sizes in a human readable
format.
cd [path] Change the current directory to [path].
cd .. Change to the parent directory (note the space between ‘cd’
and ‘..’).
cd / Change to the root directory (note the space between ‘cd’ and
‘/’).
cd ∼ Change to the home directory (determined by $HOME
environment variable).
mkdir [name] Create the directory [name] in the current working directory.
¹⁵https://twitter.com/Clemens_Elektor
¹⁶https://www.elektormagazine.com/news/bash-command-cheat-sheet
Chapter 2: Tools and hardware used in this book 19
Command Description
rmdir [name] Remove the empty directory [name] from the current working
directory.
rm [name] Remove the specified file.
rm * Remove all the files from the current working directory.
rm -r * Remove all the files and directories from the current working
directory.
cp [from] [to] Copy a file from source [from] to destination [to].
cp -r [from] [to] Copy everything including directories from source [from] to
destination [to].
mv [from] [to] Move a file from source [from] to destination [to].
mv -r [from] [to] Move everything including directories from source [from] to
destination [to].
find Search for files matching certain patterns.
sudo [command] Superuser do. Execute [command] with elevated privileges.
Allows you to do things you are not entitled to. Common
examples include:
sudo raspi-config Launch the Raspberry Pi configuration tool.
sudo reboot Safely restart your system.
sudo shutdown -h now Safely shutdown your system now.
sudo apt-get install [package] Install a package.
sudo apt-get update Update the list of packages without installing anything.
sudo apt-get upgrade Upgrade the installed packages to the versions obtained with
‘apt-get update’
sudo chown pi:root [name] Change the owner of [name] to ‘pi’ and set the group to ‘root’.
sudo su Become Superuser for more than one command.
cat [name] Show the contents of a file.
head [name] Show the beginning of a file.
tail [name] Show the end of a file.
chmod [who][+,-,=][permissions] [name] Change the permissions for a file.
chmod u+x [name] Add execute permission for the owner of the file.
chmod 777 [name] Allow every user to read, write and execute the file [name].
tar -cvzf [name] [path] Create compressed file [name] from the contents in [path].
tar -xvzf [name] Extract the contents of a compressed file.
wget [uri] Download a file from the Internet.
man [command] Show the manual page for a command.
man man View the manual page of the ‘man’ command.
nano [path] Open text editor with given file.
grep ‘string’ [name] Search inside one or more files for occurrences of ‘string’.
Jan Lamote (one of the reviewers of this book) pointed out to me that “apt-get” can also be
done with “apt”, as this is the command now being recommended. You can find more info
and a comparison between the two on this nice post by Abhishek Prakash¹⁷.
Let’s try out a few examples, open a terminal and let’s start with a directory listing “ls”. By default,
¹⁷https://itsfoss.com/apt-vs-apt-get-difference/
Chapter 2: Tools and hardware used in this book 20
the terminal will start in your home location and this command will show you the content of the
current directory, so in this case the home directory “/home/pi”.
1 $ ls
2 Desktop Documents Downloads MagPi Music Pictures Public Templates Videos
By adding a path to the ls-command, we can get the content for a given directory, for example for
the root of the system “/” or for the home directory “/home”:
1 $ ls /
2 bin dev home lost+found mnt proc run srv tmp var
3 boot etc lib media opt root sbin sys usr
4
5 $ ls /home
6 pi
To get more info we can do the same with the additional “-lha” parameters to include:
1 $ ls -lha
2 total 41M
3 drwxr-xr-x 18 pi pi 4.0K Jan 7 18:59 .
4 drwxr-xr-x 3 root root 4.0K Sep 26 01:09 ..
5 -rw-r--r-- 1 pi pi 220 Sep 26 01:09 .bash_logout
6 -rw-r--r-- 1 pi pi 3.5K Sep 26 01:09 .bashrc
7 drwxr-xr-x 7 pi pi 4.0K Jan 7 19:00 .cache
8 drwx------ 6 pi pi 4.0K Jan 7 19:00 .config
9 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Desktop
10 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Documents
11 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Downloads
12 drwx------ 3 pi pi 4.0K Sep 26 01:46 .gnupg
13 drwxr-xr-x 3 pi pi 4.0K Sep 26 01:18 .local
14 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Music
15 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Pictures
16 drwx------ 3 pi pi 4.0K Jan 7 18:59 .pki
17 -rw-r--r-- 1 pi pi 807 Sep 26 01:09 .profile
18 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Public
19 drwxr-xr-x 2 pi pi 4.0K Sep 26 01:46 Templates
Chapter 2: Tools and hardware used in this book 21
In this book we will be using the text editor “nano”, so let’s take a look into the manual with “man
nano”:
1 $ man nano
2 NANO(1) General Commands Manual NANO(1)
3
4 NAME
5 nano - Nano's ANOther editor, an enhanced free Pico clone
6
7 SYNOPSIS
8 nano [options] [[+line[,column]] file]...
9
10 DESCRIPTION
11 nano is a small and friendly editor. It copies the look and feel of Pico,
12 but is free software, and implements several features that Pico lacks,
13 such as: opening multiple files, scrolling per line, undo/redo, syntax
14 coloring, line numbering, and soft-wrapping overlong lines.
15
16 When giving a filename on the command line, the cursor can be put on a
17 specific line by adding the line number with a plus sign (+) before
18 the filename, and even in a specific column by adding it with a comma.
19
20 As a special case: if instead of a filename a dash (-) is given, nano
21 will read data from standard input.
The actual manual is longer, this is only the initial part. Press q to exit from it. Now let’s take a few
steps to:
1 $ mkdir /tmp/experimenting
2 $ ls -l /tmp/experimenting/
3 total 0
4 $ nano /tmp/experimenting/mytextfile
5 $ head /tmp/experimenting/mytextfile
6 Hello!
7 $ ls -l /tmp/experimenting/
8 total 4
9 -rw-r--r-- 1 pi pi 7 Dec 15 22:07 mytextfile
10 $ rm /tmp/experimenting/mytextfile
11 $ ls -l /tmp/experimenting/
12 total 0
• Use the tab key to auto-complete a path, e.g. type in “ls -l /t” and hit the tab-key. This will
autocomplete to “ls -l /tmp/” as there is only one directory starting with “/t”.
• Use the up and down key in the terminal to reuse one of the commands you have typed in
before.
Firefox
Raspbian comes with Chromium (from Google) pre-installed, but that’s not my preferred browser
(see “Just a thought: Switching social”), so I installed Firefox with following commands:
VNC server
When you use multiple Pi’s, only have one monitor and/or your Pi is somewhere in an unreachable
place, you can still easily work with it using a remote desktop tool. VNC server is the easiest one to
use.
Raspbian includes VNC Server by default. Only if you want to add the viewer, you will need to run
the following command in the terminal, in case you want to use the viewer on the Pi itself to start
a session to another one.
Chapter 2: Tools and hardware used in this book 23
In raspi-config select “5 Interfacing options” > “VNC” > “Yes” to enable remote VNC connections.
On your PC you’ll need to install VNC Viewer¹⁸ to connect to your Pi remotely. This application
will keep a list of all your connections. You can find the IP of your Pi with the terminal and the
“ifconfig” command.
VNC Viewer
When you first connect to a new Pi, the credentials to be used are “pi” for the username, and
“raspberry” for the password. As with all default passwords, you should change them ASAP! Open
the terminal and type the following command:
1 $ passwd
You are asked for the current password, and a new one and you’re done! BTW, you can also do the
same via “raspi-config”, option “1 Change user password”.
You will be asked for the password which is “raspberry” by default, but you should have changed
that when you first booted your Pi for obvious security reasons… When this is OK you get both a
directory listing and terminal window, both in your home directory (“/home/pi”).
To upload a file, e.g. after you compiled a Java jar-application, you can easily drag it from your PC
into the directory listing window of MobaXterm.
If you are using Linux as your workstation, you can connect directly from the terminal with the
command “ssh pi@IPADDRESS”. When this is the first login, you will need to confirm. E.g. in my
case:
1 $ ssh pi@192.168.0.160
2 The authenticity of host '192.168.0.160 (192.168.0.160)' can't be established.
3 ECDSA key fingerprint is SHA256:w4QRLobqhj98enNnqTbIpAJ6NpWiLUXLCbweHCA1Em8.
4 Are you sure you want to continue connecting (yes/no)? y
5 Please type 'yes' or 'no': yes
6 Warning: Permanently added '192.168.0.160' (ECDSA) to the list of known hosts.
7 pi@192.168.0.160's password:
8 Linux raspberrypi 4.19.93-v7+ #1290 SMP Fri Jan 10 16:39:50 GMT 2020 armv7l
9
10 The programs included with the Debian GNU/Linux system are free software;
11 the exact distribution terms for each program are described in the
12 individual files in /usr/share/doc/*/copyright.
13
14 Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
15 permitted by applicable law.
16 Last login: Sat Feb 1 12:06:00 2020 from 192.168.0.135
17
18 SSH is enabled and the default password for the 'pi' user has not been changed.
19 This is a security risk - please login as the 'pi' user and type 'passwd' to set a n\
20 ew password.
21 pi@raspberrypi:~ $
You see you even get a warning when you didn’t change the password! Oops, now you know I didn’t
do that, but in my defense, I started with a fresh Raspbian a few times for this book to clean up my
test environment, so none of these default password versions survived long… ;-)
Copying a file to and from a Pi can also be done in the Linux terminal with the “scp SOURCE
DESTINATION” command. These are a few examples to create a txt file, copy it to a Pi and copying
it back to the PC:
1 $ nano test.txt
2 $ scp /home/pi/test.txt pi@192.168.0.160:/home/pi/copied.txt
3 $ scp pi@192.168.0.160:/home/pi/copied.txt /home/pi/copied_back.txt
Wiring diagrams
The wiring diagrams in this book are made with Fritzing²⁰
²⁰https://fritzing.org/home/
Chapter 2: Tools and hardware used in this book 28
Screenshot Fritzing
Schematic drawings
Diagrams for this book were made with yEd Graph Editor by yworks²¹, a free tool to quickly draw
diagrams. They also provide commercial libraries (for Java, .NET, web) to include such drawing tools
into your software.
Screenshot yEd
²¹https://www.yworks.com/downloads#yEd
Chapter 2: Tools and hardware used in this book 29
Hardware components
Resistors
These are the base components we will need in all of our projects. And as it is impossible to keep
them separated, you will need to be able to calculate their value based on the color-coding. Most of
the resistors in use have 4 color rings and you will need this table to calculate the value.
This color-coding table is created as a JavaFX application. JavaFX is explained later in this
book. But you can take a look at the sources if you want to experiment with it or use it to
calculate the values of a resistor as described below.
Chapter_02_Tools > javafx-resistors
The most used type of resistor used in Pi- and Arduino-projects is a 330Ω to limit the power for an
LED.
Gold can never be the first one, so we need to start on the other side.
• brown (1), black (0), green (100KΩ) multiplier, gold (5) tolerance
1MΩ • 10 * 100KΩ with 5% tolerance
• = 1MΩ with 5% tolerance
LEDs
Next to resistors, LEDs are also most used in the projects in this
book. They come in all colors and sizes. A Light-Emitting Diode,
as the name says, emits light when current flows through the
diode, blocking the current flowing in the opposite direction. The
voltage drop caused by the LED mostly lays between 1.2 to 3.6
Mix of different LEDs
volts with a recommended current between 10 to 30 mA.
They have a positive and negative pin and it’s easy to remember which is the positive one. The
longest one! You have more of it ;-) In case the pins are cut off, the flat edge of the plastic cap is
the negative side. The current in the LED can only flow from the positive (anode) to the negative
(cathode) side!
As a Pi outputs 3.3V on the GPIOs and most Arduinos output 5V, we will need a resistor to limit the
voltage so we don’t damage the LED.
Chapter 2: Tools and hardware used in this book 31
RGB-LED
RGB-LEDs combine three different colors in one component. They share either a common cathode
(-) or anode (+). Luckily you can’t damage them by connecting them the wrong way, so you can
quickly check with a fixed power pin from the Pi (don’t forget the resistor!). As you will see in
“Chapter 9: Pi4J > Digital GPIO input and output examples > Example 1: Digital output with RGB-
LED” the different colors don’t have the same brightness and you’ll need to check the datasheet to
define the correct resistors to be used for every pin.
Chapter 2: Tools and hardware used in this book 32
Pins of an RGB-LED
LED strips
Led strips are available in these two most used “flavors”: WS2812B (improved version of the WS2811,
also known as the AdaFruit NeoPixel) versus WS2813 and their main difference is the number of
connections (3 versus 4).
Two important notes for LED strips:
• it’s not enough to connect power to them, they won’t do anything until a controller sends data.
• they need a lot of power so don’t take power from the Pi, but use an external power supply.
To know which power supply you need, some calculation is required… Check the datasheet of the
strip you are using to know how much current a single LED in the strip uses at maximum brightness.
As an example, take one which uses 60mA max. per LED. By the way, this is only the case for full
white, so the real use will be lower if you are using colors only.
Chapter 2: Tools and hardware used in this book 33
If we only want to do some testing, we can use a short piece with e.g. only 10 LEDs. So this would
require 0.6A (600mA) at full brightness. But even this is too much for the Pi. The 5V pin gets its
power from the USB power supply, which is also used by the Pi-system itself, of course, leaving
only a few hundred mA left for this pin.
For an Arduino, it depends on the type and power supply but about 400mA to 800mA should be
available. And indeed as I found out myself while setting up the example project described in
“Chapter 11: Message Queues”, a short strip can be powered directly from an Arduino.
Side remark, that Arduino example didn’t work at some point because I had the board
connected to my PC. So the board was powered by my PC, while I used a long LED-strip
with a separate power supply. Because they didn’t share the same ground, the data was
completely messed up and the LEDs didn’t show the effect I was expecting. So remember to
ground them together!
Conclusions
• Pi: connect the power for the led strip in all cases to a separate power supply.
• Arduino: OK for testing a short strip.
• Make sure board and strip share the same ground.
Chapter 2: Tools and hardware used in this book 34
Watch out for eye damage while experimenting with strips as they can be very bright!
This chart is based on the number of engineering students (electromechanics, digital arts, and
entertainment, electronics-ICT, multimedia and communication technology,…) in Flanders, Belgium
. Thanks to CoderDojo and other STEAM-initiatives, this kind of education gained popularity and
the female group grew from 15% to 21% in all these years.
Of all the students (240.332) who started high school in 2018-2019, only 16.560 or 7% started in this
engineering direction, while it almost guarantees you to find a fun and challenging job! As STEAM
will become more and more important in the future, in a society that relies heavily on technology,
we need to inspire more people…
A long intro to point out the fact I started “educating” kids not only in CoderDojo, but also at work
with children of colleagues in a First Lego League team. That’s the moment you discover you know
nothing… or at least not what kids are asking. Also, the moment you start experimenting with new
things and a new world opens its doors for you. For me, that was the moment I discovered Arduino,
Raspberry Pi, Mindstorms and many more. Because I believe in the power of knowledge sharing, I
also started blogging, writing, presenting and again discovered new worlds.
You can only explain something if you master it or research, try out, fail, restart, document. Exactly
what I tried to do for this book…
https://coderdojo.com/
Publications on www.vlaanderen.be/publicaties > “Hoger onderwijs in cijfers”
Science, Technology, Engineering, Arts and Mathematics
http://www.firstlegoleague.org/
Just a thought: Learn by educating 37
old, but someone who has been in a CoderDojo since age 6 might be a lot faster to transition. Projects
like EduBlocks can be an easy step up, to take away the “fear” of written code, by combining blocks
and Python into one editor. MakeCode by Microsoft offers a similar function with Javascript and so
on. Seeing the effects of your block-based code on the written code and vice versa is a very strong
learning experience.
You are “Raspberry Pi Certified”. What does this mean and how did you achieve this?
Raspberry Pi has a training program for educators interested in teaching physical computing called
Picademy. For three days, a group learns all about using the Pi in an educational context, how to
code basic things, but also how to explain them and utilize the Pi in projects. I love that it combines
technical, creative and didactical knowledge into one awesome program. I would suggest anyone
into code education (teachers, Dojo leads, library educators…) to sign up. It is free, as long as you
are willing to travel to the UK for it. I was the first Belgian educator to participate, but I’m happy
that others have followed and I hope many more will.
Why is now the perfect time to learn to program?
We live in a day where tech has more and more become a closed system. We use phones with apps
on them all the time, we have smart technology in our houses. But very few people understand how
it works, and feel a lack of control over them. To me, learning to program means taking back that
control and breaking open the black box. Not everyone should become a professional programmer,
but every child, teen or adult can benefit from understanding (basic) coding logic.
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
I would need more hours in a day/week but I’ve been wanting to assemble an RGB light-up scarf
for a while now, as well as a Raspberry Pi-powered selfie booth for my dog.
https://twitter.com/LimsKaren
https://scratch.mit.edu/
https://code.org/
https://blockly.games
https://edublocks.org/
https://www.microsoft.com/en-us/makecode
Chapter 3: Choosing an IDE
An IDE (= Integrated Development Environment) is your best friend while developing applications.
It will help you to write the correct code and compile it to a running application. Some of the most
used ones are IntelliJ IDEA, Visual Studio Code, NetBeans and Eclipse.
Apache NetBeans²² is a free and open-source IDE which you can use for Java, JavaScript, PHP,
C/C++… The same goes for the Eclipse IDE²³. Both are very popular editors but I will focus on two
other ones. Selecting an IDE is a very personal thing. Once you are familiar with one and know the
shortcuts to work fast, it will be hard to switch. So try them out, find which one fits best to your
needs, go for it and don’t look back ;-)
I started using Eclipse when I first programmed Java but switched a few years ago to IntelliJ IDEA
(for Java) and Visual Studio Code (for Java, JavaScript, and experimenting). These tools just seem to
work better for (with) me.
²²https://netbeans.org/
²³https://www.eclipse.org/ide/
Chapter 3: Choosing an IDE 40
IntelliJ IDEA
IntelliJ IDEA is a commercial product built by the company JetBrains, headquartered in the Czech
Republic. They sell a lot of developer tools, but IntelliJ IDEA is the most known one and it is the
most used Java IDE by professional developers. There is a free version (the Community edition)
which can be used for Java and Android development, while the Ultimate edition is a paid version
with additional features, as you can see on the download page²⁴.
Code completion (= hinting) and powerful refactoring tools are the main advantages of an IDE which
help you to write your code faster as the possible methods are shown, including the parameters.
Another great feature of IDEA is the visualization of the parameter name in your code, so you can
easily check if you used the correct value when calling a method.
Opening a project
In the next window select the directory of the project you want to open and click OK.
IntelliJ IDEA will need some time to load the Maven dependencies (see Chapter 6 for more info),
and when this is finished everything is ready to explore the files and start coding yourself.
Chapter 3: Choosing an IDE 42
In case you have multiple Java SDK’s installed, you may need to help IntelliJ IDEA to define which
one to use.
Keep in mind you will need at least JDK 11 for the Java example projects. You can use the same
one we will be using on the Pi (Liberica JDK from BellSoft, see Chapter 4 on how to get and install
this JDK) or use the latest one from AdoptOpenJDK²⁵. You can define the SDK to be used for every
project via the “Project Structure” button (SHIFT+CTRL+ALT+S).
In the next screenshot, you can see an open JavaFX project from the examples.
• Left - Project window: here you can browse all the files in your project
• Middle - Editor window: containing an open Java file
• Right - Maven window: more info in Chapter 6, but click here on
* “Plugins > javafx > javafx:compile” to compile the code to bytecode which will also reveal if
the code is OK
* “Plugins > javafx > javafx:run” to start the application
In some cases when the code doesn’t want to start or build, select “Build” in the top menu
and click “Rebuild Project” to clean up everything inside the project. When this is done, you
can try to run your project again.
²⁵https://adoptopenjdk.net/
Chapter 3: Choosing an IDE 43
If you’re interested in Java features since Java 8, then you probably want to look at:
In terms of up-and-coming things, I’m interested in Records and Pattern Matching. Also, I think it’s
worth taking a look at Kotlin, it’s a very pleasing language to code in.
Why is now the perfect time to learn Java?
Java is not going anywhere any time fast! And even if no-one developed anything new in Java from
now on (which is certainly not the case!), there are so many Java applications and so much Java code
out there that there’s plenty to keep us in well-paid employment for as long as we want to be coders!
Maybe that’s not the most exciting reason to learn a language but it’s certainly the most pragmatic.
But on top of that, the six-monthly release cadence is really helping to move the language forward
faster, and with feedback from real developers like us, so it’s a really great time to be involved with
the language and help to drive it in a direction that works for us.
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
Er none! I’ve traditionally always used my so-called free time for community and advocacy, so I
tended to go to user groups, write blog posts, and work on my presentation skills when I wasn’t
doing my 9-5 job. Now, I don’t even really do that because the reality of having small children is I
just don’t have the time or energy for anything other than trying to keep them alive and possibly
entertained. I have to scratch my development/technology itches during my day job. Luckily, as a
developer advocate, I have a reasonable amount of flexibility in what I spend my time on, and I can
use work time to learn new stuff, especially if it’s relevant to the Java/JVM community.
https://twitter.com/trisha_gee
Chapter 3: Choosing an IDE 46
As described further, you can use VSC on PC but work with files on the Pi, but you can also install
VSC on the Pi itself if you want to program on it. As the official version is only for 64-bit PCs and
Raspbian only has a 32-bit operating system version - although the Pi 4 has a 64-bit processor - this
will not work. Luckily we can still find an earlier version of VSC which is 32-bit and compiled for
the Pi! You can install in three easy steps:
1 $ cd /home/pi/
2 $ wget https://github.com/stevedesmond-ca/vscode-arm/releases/download/1.28.2/
3 vscode-1.28.2.deb
4 $ sudo apt install ./vscode-1.28.2.deb
²⁶https://github.com/Microsoft/vscode
²⁷https://code.visualstudio.com/Download
Chapter 3: Choosing an IDE 47
Java projects in VSC can be easily started with the popup “Run|Debug” buttons. They
appear automatically above the main-method. If you use VSC on the Pi you need to
keep in mind it will take some time before this is shown after loading a project!
Click on the “Extensions” button in the left bar. With the search box on top, you can find extensions
in the Marketplace. For Java development, you will need some additional ones. Not all are required
but as you can see I installed a bunch of them. “Language Support for Java” by RedHat is the most
important one.
Chapter 3: Choosing an IDE 49
Take a look at this Java info page on the VSC website³⁰ for more detailed info on this topic.
When this is done, hit F1 for the “Search Everywhere” popup on top and search for “Remote-SSH”
and hit enter.
³⁰https://code.visualstudio.com/docs/languages/java
Chapter 3: Choosing an IDE 50
In my case, I already have two Pi’s addresses configured, but to add one click on “Add New SSH
Host…”
You will need to know the IP address if your Pi and SSH needs to be enabled (see Chapter 2: Tools).
By default you can connect with username “pi” and password “raspberry”, but don’t forget to change
that if you care about security (and we all do… but still forget to change default passwords…).
When you have entered the ssh login command with the IP address of your Pi, in my case “ssh
pi@192.168.0.235”, you will be asked for the password. It will take some time for VSC to install the
necessary files on the board so it can be used for remote development. You will see on the lower left
of the IDE that it’s busy…
… or ready.
Chapter 3: Choosing an IDE 51
Connection established
Now you can open a file or directory from the Pi on your PC in VSC just as you would be working
on the Pi itself.
Running the code can be done the same way in the terminal of VSC and will be executed on the
board itself. In this screenshot, you see the Python code from “Chapter 8: Bits and Bytes”.
When working on this chapter, I was wondering if I should create a timeline in Photoshop
or Illustrator. But being a developer, it needed to be done with code of course! And it took
me only two hours to make something which I can easily change to different data sets. Most
of that time was needed to research how to draw with “javafx.scene.shape.Line” as I hadn’t
done this before.
The finished application is part of the sources:
chapter_04_Java > java-timeline
Take a look at the sources in DataSets.java and you will see how easy it was to change the
markers on the timeline to create the different images for this chapter, for example for the
above image:
History
Timeline of Java
The development of the Java language started in 1991 with the first public release by Sun
Microsystem in 1995. From 2007 on, the major part of the Java core source code has been available
as open-source.
When Oracle acquired Sun Microsystems in 2009-2010 they also became the owner of Java.
Google used Java as the main programming language for Android applications, as Android systems
are based on Linux.
Say hello to Duke, designed by artist Joe Palrang while he was Art Director
at Sun. It was originally a “software agent” designed to perform tasks for the
user, just like Clippy the animated paper clip from Microsoft.
Duke is now the official mascot for the Java language even appearing in
comics, on coffee cups, t-shirts, etc. The graphic specification of Duke has
been open-sourced³¹ by Sun on November 13, 2016.
Duke
³¹https://hg.openjdk.java.net/duke/duke/
Chapter 4: About Java 56
1 Hello World!
This .java-file is the file you will be working in to write code (for example on a Windows PC in
IntelliJ IDEA). But to run it on different platforms (for example on the Raspberry Pi), it needs to be
converted to byte code. The byte code file (with the extension .class) is the result of compiling your
source code file(s) to something which can be used by the Java runtime on each platform.
When opening such a class-file in e.g. Notepad++ you get this:
It’s no longer readable for us but optimized for the runtime environment.
Chapter 4: About Java 57
Version history
The Java-architects always made sure improvements and new features in Java didn’t break existing
applications. Because of this, you can still run old Java applications on newer versions with none or
minimal changes. This is one of the big differences with Python were applications made for Python
2 are incompatible with the completely refactored version 3. On the other hand, the version number
and naming of the Java releases took some strange turns as you can see in this timeline:
Timeline of Java
Abbreviations used:
Between the versions 5 till 9, new versions of Java were released with big intervals. With current fast
changes with cloud platforms, big data, artificial intelligence, etc. a faster release cycle was needed
to be able to align new Java features with new demands.
This led to a big change in the whole Java ecosystem in recent years. A lot of companies contribute
to the OpenJDK project pushing it forward and releases are now scheduled every six months! All
new features which are finished at the release date, get included, others just have to wait till the
next one. This is a completely different approach compared to the earlier days where a release was
only done when all scheduled new features were finished.
If you keep an eye on the changes in new releases, you can decide for yourself if you want to update
your development and runtime JDK to the latest one, or just stick to the one you are using if you don’t
need one of the new features. But if you care about security and the best performance, following the
release cycle will offer you the best results as Java gets improved continuously!
Chapter 4: About Java 59
JDK providers
All the sources of the Java Development Kit itself are open source and can be found on GitHub >
OpenJDK³². So if you would like, you can build your own JDK from these sources. Luckily a lot of
others have done this already and provide up-to-date compiled versions.
A full list is available on the jchoice website³³. Let’s take a quick look at some of them.
Oracle
This is the “mother” of all JDK’s, but the most expensive one for commercial use as you need a
contract with Oracle for non-personal and non-development use.
On the other hand, Oracle is still the main contributor to OpenJDK. There is a nice overview of the
differences between Oracle JDK and OpenJDK on this post on the Baeldung site³⁴.
AdoptOpenJDK
If you want to have the most up-to-date JDK for your development PC, this is the place to be³⁵. All
the binaries and scripts provided here are free.
On the AdoptOpenJDK website, you will find multiple versions for different platforms, all ready to
install with a few clicks.
different platforms. For embedded systems, they can provide “tailor-made” JDK versions tested for
that specific platform.
Zulu is used on Microsoft Azure to run Java applications in the cloud.
BellSoft Liberica
Similar to the other ones, BellSoft³⁷ compiles from the OpenJDK sources, but they include JavaFX
into the JDK in specific platform versions. JavaFX was once a part of Java but has become a separate
project.
Above all, BellSoft also provides a version specifically made for the Raspberry Pi. Further in this
book, we will use JavaFX to build GUIs (Graphical User Interface) for the Pi, so this is the SDK we
will be using on the Pi in this book.
In one of the next steps, make sure to select the option “Set JAVA_HOME variable”. By doing so, we
will be able to start Java easily in the terminal.
³⁸https://adoptopenjdk.net/
Chapter 4: About Java 63
Once the installation is completed, you can open a “Command Prompt” via the start menu. Type
“java –version” and you will get the version.
But you can also use SDKMAN³⁹ to change between different SDK versions easily. According to this
blog post⁴⁰, it also works on Windows, but I didn’t try it out myself. The tool also provides a list
overview of the available SDKs through SDKMAN:
³⁹https://sdkman.io/
⁴⁰https://ngeor.com/2019/12/07/sdkman-windows.html
Chapter 4: About Java 64
And within the shell you can choose to use a different SDK version, for instance, if you want to test
if your application can run with another one:
The Java versions used here, can only be used on the Pi’s with an ARMv7 or ARMv8
processor. The oldest Pi’s have an ARMv6 that has a completely different architecture which
is not supported by these Java JDKs.
On the Wikipedia site you can find a nice overview⁴¹ of the different Raspberry Pi models
and which instruction set they use. The ones with ARMv6 are not a perfect fit for our Java
experiments.
In the release notes of Raspbian⁴² you can see that the version of 2019-06-20 includes OpenJDK Java
11.
1 2019-06-20:
2 * Based on Debian Buster
3 * Oracle Java 7 and 8 replaced with OpenJDK 11
So we are good to go! A recent version of Java is ready to use! But… as we will be using JavaFX later
in this book, we will replace the pre-installed JDK with Liberica JDK provided by BellSoft, which
includes JavaFX.
Installing a new JDK is easy once you know where to get it. These are the steps needed to install
version 13 of Liberica JDK.
First, we will check the current version so we can validate it after the installation. With Raspbian
Buster this will be the result:
1 $ java -version
2 openjdk version "11.0.3" 2019-04-16
3 OpenJDK Runtime Environment (build 11.0.3+7-post-Raspbian-5)
4 OpenJDK Server VM (build 11.0.3+7-post-Raspbian-5, mixed mode)
Now we will download the version we want, and replace the existing one. Check the Liberica JDK
pages on the BellSoft website⁴³ and copy the link to the deb-file of the version for the Pi you want
to use. This is the example for the JDK 13 version:
⁴¹https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications
⁴²http://downloads.raspberrypi.org/raspbian/release_notes.txt
⁴³https://bell-sw.com
Chapter 4: About Java 66
1 $ cd /home/pi
2 $ wget https://download.bell-sw.com/java/13/bellsoft-jdk13-linux-arm32-vfp-hflt.deb
3 $ sudo apt-get install ./bellsoft-jdk13-linux-arm32-vfp-hflt.deb
4 $ sudo update-alternatives --config javac
5 $ sudo update-alternatives --config java
When this is done, we can check the version again and it should look like this:
1 $ java --version
2 openjdk version "13-BellSoft" 2019-09-17
3 OpenJDK Runtime Environment (build 13-BellSoft+33)
4 OpenJDK Server VM (build 13-BellSoft+33, mixed mode)
1 $ cd /home/pi/JavaOnRaspberryPi/chapter_04_Java/scripts
2 $ sh install_liberica_13.sh
Chapter 4: About Java 67
1 $ jshell
2 | Welcome to JShell -- Version 11.0.4
3 | For an introduction type: /help intro
4
5 jshell> /help intro
6 |
7 | intro
8 | =====
9 |
10 | The jshell tool allows you to execute Java code, getting immediate results.
11 | You can enter a Java definition (variable, method, class, etc), like: int x = 8
12 | or a Java expression, like: x + x
13 | or a Java statement or import.
14 | These little chunks of Java code are called 'snippets'.
15 |
16 | There are also the jshell tool commands that allow you to understand and
17 | control what you are doing, like: /list
18 |
19 | For a list of commands: /help
20
⁴⁴http://tutorials.jenkov.com/java/modules.html
Chapter 4: About Java 68
In version 11 the JavaFX library was removed from the JDK and moved to a separate project (See
Chapter 7).
On this website made by Marc R. Hoffmann⁴⁵ you can compare the differences between the Java
versions in a very detailed way.
Switch Expressions
1 switch (day) {
2 case MONDAY:
3 case FRIDAY:
4 case SUNDAY:
5 System.out.println(6);
6 break;
7 case TUESDAY:
8 System.out.println(7);
9 break;
10 case THURSDAY:
11 case SATURDAY:
12 System.out.println(8);
13 break;
14 case WEDNESDAY:
15 System.out.println(9);
16 break;
17 }
1 switch (day) {
2 case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
3 case TUESDAY -> System.out.println(7);
4 case THURSDAY, SATURDAY -> System.out.println(8);
5 case WEDNESDAY -> System.out.println(9);
6 }
⁴⁶http://openjdk.java.net/jeps/325
⁴⁷http://openjdk.java.net/jeps/354
Chapter 4: About Java 70
Now you can use triple ‘”’ to start and end a String definition, but these must be on separate lines.
You can add tabs to structure your text. Here is an example:
⁴⁸https://openjdk.java.net/jeps/355
⁴⁹https://openjdk.java.net/jeps/358
Chapter 4: About Java 71
With this new functionality, the error will provide more info about the object which caused the
error, so you can quickly spot the error in your code. For instance:
1 $ cd /home/pi
2 $ nano HelloWorld.java
Java requires us to “package” our code in a class. This has the same name as the file, so in this case,
we need to start with “public class HelloWorld”.
A Java application also needs an “entry point”, the main class which is started and can call all other
methods, that’s the second line we need to add: “public static void main (String[] args)”.
Here we can add any code we want. In this case, we start with creating a String variable “txt” which
holds “Hello World”. Notice each line needs to end with a “;”.
“System.out.println(txt)” is similar to “console.log” in JavaScript or “print” in Python.
⁵⁰https://notepad-plus-plus.org/
Chapter 4: About Java 73
When you are doing this on the Pi, and are finished with typing the code in “nano”, click “CTRL+X”
to exit, “Y” to save and “ENTER” to write to the file.
To execute this code, we need to start Java with the name of the file we just created, as an argument:
1 $ java HelloWorld.java
2 Hello World
And there it is… our first working Java code on a Pi! :-)
Although you can write all the code from these examples directly on the Pi or your
PC with nano or any other text file editor, you can of course also do the same in an
IDE.
When doing so, you will immediately notice the advantage of the code hinting.
For instance, if you want to get the first 4 characters of the txt-variable, you are
presented with a list of possible methods you can use on a String.
1 $ cd /home/pi
2 $ nano MainArguments.java
Now we can start the application and provide it any number of extra arguments, which are provided
to the Java code as an array of Strings (= String[]). From this array, we can get the number of items
(= args.length) and use a for-loop to cycle through all the arguments.
1 $ java MainArguments.java
2 Number of arguments: 0
3
4 $ java MainArguments.java "Hello World" "Bye"
5 Number of arguments: 2
6 First argument: Hello World
7 Argument 1: Hello World
8 Argument 2: Bye
Depending on the type of number, they use more or less memory. In most cases ints are used, but
when you need to store e.g. prices, you would use a float. When assigning a value to either a float
or a double, the number has to end with an “F” or “D” (see example). This helps Java to understand
what you want to achieve.
We create both the example float and double with 20 decimals to see the number of decimals that
are really stored in the variable.
Chapter 4: About Java 75
1 $ cd /home/pi
2 $ nano NumberValues.java
3
4 public class NumberValues {
5 public static void main (String[] args) {
6 int intValue = 2;
7 float floatValue = 1.12345678901234567890F;
8 double doubleValue = 1.12345678901234567890D;
9
10 System.out.println("Integer: " + intValue);
11 System.out.println("Float: " + floatValue);
12 System.out.println("Double: " + doubleValue);
13
14 System.out.println("Multiply: " + (intValue * floatValue)
15 + ", rounded: " + Math.round(intValue * floatValue));
16 }
17 }
18
19 $ java NumberValues.java
20
21 Integer: 2
22 Float: 1.1234568
23 Double: 1.1234567890123457
24 Multiply: 2.2469137, rounded: 2
1 $ cd /home/pi
2 $ nano IfThenElse.java
3
4 public class IfThenElse {
5 public static void main (String[] args) {
6 // Compare integer value
7 int piHeaderVersion = 1;
8
9 // We don't change the variable in this example,
10 // but here could be some code to define this variable based on,
11 // for instance, a hardware check.
12
Chapter 4: About Java 76
13 if (piHeaderVersion == 1) {
14 System.out.println("Header version 1 is used on original Model B");
15 } else if (piHeaderVersion == 2) {
16 System.out.println("Header version 2 is used on Model A and Model B"
17 + " (revision 2)");
18 } else if (piHeaderVersion == 3) {
19 System.out.println("Header version 3 is used on Model A+, B+, Pi Zero,"
20 + " Pi Zero W, Pi2B, Pi3B, Pi4B");
21 } else {
22 System.out.println("Sorry, header version " + piHeaderVersion
23 + " is not known");
24 }
25
26 // Compare strings
27 String string1 = "Hello world";
28 String string2 = "Hello" + " " + "world";
29 String string3 = "Hello World";
30
31 System.out.println("Are string1 and string2 equal? "
32 + string1.equals(string2));
33 System.out.println("Are string1 and string3 equal? "
34 + string1.equals(string3));
35 System.out.println("Are string1 and string3 equal ignoring the case? "
36 + string1.equalsIgnoreCase(string3));
37
38 if (string1.equalsIgnoreCase(string3)) {
39 System.out.println("string1 and string3 are equal ignoring the case");
40 }
41 }
42 }
43
44 $ java IfThenElse.java
45
46 Header version 1 is used on original Model B
47 Are string1 and string2 equal? true
48 Are string1 and string3 equal? false
49 Are string1 and string3 equal ignoring the case? true
50 string1 and string3 are equal ignoring the case
The line starting with “//” is a comment line, so it is ignored by Java. By changing the piHeaderVer-
sion to 2, 3 or something else, you will see the text output of the several if blocks.
The second part of this example script shows how to compare string-values. Because a String is an
Chapter 4: About Java 77
object, you can only correctly compare the content (= text) of the String by using the “equals()” or
“equalsIgnoreCase()” methods.
1 $ cd /home/pi
2 $ nano IfThenElse.java
3
4 public class EnumSwitch {
5 public static void main (String[] args) {
6 // Compare integer value
7 HEADER_VERSION piHeaderVersion = HEADER_VERSION.TYPE_2;
8
9 // Same as before, we don't change the variable in this example.
10
11 switch(piHeaderVersion) {
12 case TYPE_1:
13 System.out.println("Header version 1 is used on original Model B");
14 break;
15 case TYPE_2:
16 System.out.println("Header version 2 is used on Model A and Model B"
17 + " (revision 2)");
18 break;
19 case TYPE_3:
20 System.out.println("Header version 3 is used on Model A+, B+,"
21 + " Pi Zero, Pi Zero W, Pi2B, Pi3B, Pi4B");
22 break;
23 default:
24 System.out.println("Sorry, header version " + piHeaderVersion
25 + " is not known");
26 }
27 }
28
29 enum HEADER_VERSION {
30 TYPE_1, TYPE_2, TYPE_3, UNKNOWN;
31 }
32 }
Chapter 4: About Java 78
33
34 $ java EnumSwitch.java
35 Header version 2 is used on Model A and Model B (revision 2)
Instead of if/then/else we are now using switch/case/default, resulting in more readable code. This
is also easier to use and maintain as we know exactly which are the possible values for the header
versions.
Don’t forget to add the “break;” lines in each case. Try removing them and re-run the example.
1 $ java EnumSwitch.java
2 Header version 2 is used on Model A and Model B (revision 2)
3 Header version 3 is used on Model A+, B+, Pi Zero, Pi Zero W, Pi2B, Pi3B, Pi4B
4 Sorry, header version TYPE_2 is not known
Not want we wanted! All the cases after the valid one are returned now… That’s also the reason we
don’t need to add a break in the default-block as this is the last one anyhow.
Using methods
Now let’s use some separated methods so we can keep the code simple and easy to read and
understand. Each method does one specific thing, with or without input values.
1 $ cd /home/pi
2 $ nano UsingMethod.java
3
4 import java.text.SimpleDateFormat;
5 import java.util.Date;
6
7 public class UsingMethod {
8 public static void main (String[] args) {
9 System.out.println("2 x Raspberry Pi 4 4Gb, price: "
10 + getTotal(2, 59.95F) + " Euro");
11
12 System.out.println("Current date and time is: " + getNow());
13 }
14
15 public static float getTotal(int quantity, float price) {
16 return quantity * price;
17 }
18
19 public static String getNow() {
20 return new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date());
Chapter 4: About Java 79
21 }
22 }
23
24 $ java UsingMethod.java
25
26 2 x Raspberry Pi 4 4Gb, price: 119.9000015258789 Euro
27 Current date and time is: 2019.12.03 12:35:23
First look at the import-lines. Because we use some methods which are not part of basic Java, we
need to tell our program which additional classes need to be imported.
Then two methods are defined:
By calling these methods from the main method, we can keep the code in this main-method very
clean and readable.
Using objects
Java is an object-oriented programming language. This means we can turn any part of our code into
an object with its variables and methods. For instance, let’s create a program containing a shopping
cart list with items.
This example uses some methods which are not part of “base” Java. That’s why our code
starts with the import-lines to make clear where ArrayList and List can be found.
Further in this book, not all imports will be included in the code examples, to keep everything
nice and readable. If you use an IDE, you will be warned of the missing imports. Look into
the GitHub sources of each example for the full code.
1 $ cd /home/pi
2 $ nano UsingObject.java
3
4 import java.util.ArrayList;
5 import java.util.List;
6
7 public class UsingObject {
8 public static void main (String[] args) {
9 List<ShoppingCartItem> items = new ArrayList<>();
10 items.add(new ShoppingCartItem("Raspberry Pi 4, 4Gb", 1, 59.95F));
Chapter 4: About Java 80
54
55 $ java UsingObject.java
56 Raspberry Pi 4, 4Gb
57 1 x 59.95 = 59.95 Euro
58 Micro-HDMI cable
59 2 x 5.9 = 11.8 Euro
60 Raspberry Pi 4 power supply
61 1 x 9.95 = 9.95 Euro
62
63 Total for shopping cart:
64 81.70000076293945 Euro
The class “ShoppingCartItem” is an object which can hold the data for each item on the shopping
list. The constructor “ShoppingCartItem(String name, int quantity, float price)” enables us to make
an item that has a name, quantity, and price. The method “getTotal()” inside the item will return the
total cost for the item based on quantity and price.
In the main method, we can now easily create a list with objects of type “ShoppingCartItem” and
add a few of them in the list. With a for-loop, we can read all the items inside the list and calculate
the total value.
In the “System.out.println” two special characters are used for better readable output:
So remember, breaking your code into smaller portions, with “real” variable names will help
you and your colleagues to understand, maintain, improve and extend the code.
1 1,Ada,Gomez,40,Mabvob Pike,Radafso,LA,60500
2 2,Bernard,Jordan,28,Dotcu Court,Cewbufbim,MS,17422
3 3,Mittie,Vaughn,64,Nandac Mill,Patunif,RI,81182
4 4,Miguel,Clarke,39,Liac Boulevard,Deguci,NH,32207
5 ...
Let’s write a program to read this CSV-file line by line and convert each line to an object which is
added to a list of persons:
⁵¹http://www.convertcsv.com/generate-test-data.htm
Chapter 4: About Java 83
1 $ cd /home/pi
2 $ nano UsingObject.java
3
4 import java.io.BufferedReader;
5 import java.io.File;
6 import java.io.FileReader;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 public class ReadTextFile {
11 public static void main (String[] args) {
12 List<Person> persons = loadPersons();
13
14 System.out.println("Number of persons loaded from CSV file: "
15 + persons.size());
16
17 for (Person person : persons) {
18 System.out.println(person.getFullName() + ", age: " + person.getAge());
19 }
20 }
21
22 public static List<Person> loadPersons() {
23 List<Person> list = new ArrayList<>();
24
25 File file = new File("resources/testdata.csv");
26
27 try (Scanner scanner = new Scanner(file)) {
28 while (scanner.hasNextLine()) {
29 list.add(new Person(scanner.nextLine()));
30 }
31 } catch (FileNotFoundException ex) {
32 System.err.println("Could not find the file to be loaded");
33 }
34
35 return list;
36 }
37
38 public static class Person {
39 private int id;
40 private String firstName;
41 private String lastName;
42 private int age;
43 private String street;
Chapter 4: About Java 84
Just like in the UsingObjects-example, we use an object to store the data of each line in the CSV file,
in this case, the object “Person”.
Within the loadPersons-method:
Chapter 4: About Java 85
Using streams
Streams were introduced as a new feature in Java 8. These allow you to perform a series of steps or
actions on an object.
Let’s extend the ReadTextFile example with some extra functions…
First, we need to add extra imports:
1 import java.util.IntSummaryStatistics;
2 import java.util.stream.Collectors;
Of course, we need to add the methods “countFirstName” and “getAgeStats” which are used in this
extra code in the “main”-method:
As you see, we start by converting the list into a stream, by adding “.stream()” behind the “persons”-
list. We can further handle that stream step-by-step to obtain certain results.
• countFirstName
* filter is used to get all the persons with the given first name
* collect is used to make a list of all the matching persons
* size returns the number of items in the collected list
• getAgeStats
* mapToInt is used to only use the ages from all the persons
* summaryStatistics returns an IntSummaryStatistics-object from the list from which we can
get different values
When we run this same application again now, we get this output:
Chapter 4: About Java 87
1 $ java ReadTextFile.java
2 Number of persons loaded from CSV file: 100
3 Ada Gomez, age: 40
4 Bernard Jordan, age: 28
5 Mittie Vaughn, age: 64
6 Miguel Clarke, age: 39
7 ...
8 Alexander McCoy, age: 46
9 Callie Fitzgerald, age: 32
10 ------------------------------------------------
11 Number of persons with first name
12 * 'Matthew': 2
13 * 'Charlotte': 4
14 ------------------------------------------------
15 Minimum age: 18
16 Maximum age: 65
17 Average age: 42.78
What’s next?
Have fun! Experiment! Extend and break the examples! ;-)
You can only learn a programming language by using it…!
One of the best Java learning sites is tutorials.jenkov.com. If you want to learn more about the Java
“eco-system”, you’ll find plenty of information on this site! This site is a project of Jakob Jenkov, who
is one of those experts which in almost every Java-experts-to-follow-list on Twitter or blogs.
Jakob Jenkov, @jjenkov, Independent Software Architect, owns jenkov.com, Co-founder +
CTO of Nanosai
What is your history in the Java world?
I learned Java during university in 1995-1997 and started working with Java professionally from
1999. I started writing Java tutorials around 2005-2006 because I felt there were areas of Java that
could be covered better.
How did you start and maintain your tutorial website?
I just started with a few topics I felt needed a bit more coverage - and which were interesting for me to
study in more detail. Then the content just grew from there. However, as the body of content grows
larger, keeping it up-to-date with new developments in the languages, APIs, frameworks, methods,
etc. - is a growing task. For instance, from Aug. 2018 and until now (Feb. 2020) the majority of the
effort I have put into the website has gone into updating existing tutorials. That is why regular
readers might not have seen so many new topics added. I mostly maintain it in my spare time, and
time in between consulting contracts.
What is your motivation to do this?
Well, at first I just wanted to see if there would be any readers. As I started getting readers, I was
hoping that maybe it could be a living income. However, it takes a lot of traffic to make money
enough from ads to make a living comparable to having a normal developer job (if you live in
Europe or the US at least). Most websites don’t have that level of traffic. Now I mostly write about
what I anyways need to learn e.g. for work or other projects, so I am not just plowing through tons
of technology without a purpose. And - every time I need to Google something for a problem at
work and find somebody else’s thorough solution to that problem, it confirms to me that sharing
knowledge with everyone else is a good thing :-)
I don’t have a wife and children, so I have more extra time than many others.
What are the biggest recent changes in Java?
In my view, Java is evolving towards a smaller footprint (smaller JDK), higher performance and
more control. Java is also evolving towards building standalone applications with the Java platform
included. The various APIs become more “optional”, meaning if you don’t use them you can leave
them out of your application distribution. APIs like Java EE and JavaFX which were considered
“core” Java before, have been separated out and will take on a life of their own. Both are still very
popular though.
I believe this development is good in that sometimes what we believe is “the best way” to do
something now, turns out to be a bad way when we get more experience with it. This way those
Chapter 4: About Java 89
bad parts are not an integral part of the JDK anymore. This will unfortunately also lead to more
fragmentation of the community though, among various frameworks and toolkits.
Why is now the perfect time to learn Java?
The “minification” evolution of Java means that you don’t have to learn a thousand topics anymore
to learn the basics of Java. With serverless Java support in e.g. AWS Lambdas and in Google App
Engine you might not even have to learn all of Java EE anymore, or learn how to use a Java web
container like Tomcat, Jetty, Wildfly, etc. In other words, you need to learn less of Java to be effective
with Java than you did 10 years ago.
Java is already a strong platform for web applications, microservices, data streaming, and other
things server-side. Additionally, JavaFX can now run on Windows, Linux, Mac, iOS, Android /
Chromebook and Raspberry Pi. This makes Java a viable native GUI app platform and language too.
Which DIY-programming-electronics-project are you working on?
None. I am primarily a “software enthusiast” :-) Though I find mobile computing very interesting
since we almost always carry this device around with us everywhere. But I don’t see myself inventing
a new mobile phone :-D
http://tutorials.jenkov.com
https://twitter.com/jjenkov
http://jenkov.com
http://nanosai.com
Chapter 5: Raspberry Pi pinning
Connecting electronic components to the Pi is done via one or more of the 40 pins in the so-called
header.
Let’s take a look at the Raspberry Pi history and its versions to better understand what is possible
with these GPIOs. The following images and tables in this chapter are all generated from the open-
sourced Java library PiHeaders on GitHub⁵² and can be used as a Maven dependency⁵³.
40-pins header
⁵²https://github.com/FDelporte/PiHeaders
⁵³https://mvnrepository.com/artifact/be.webtechie/pi-headers
Chapter 5: Raspberry Pi pinning 91
The image visualizing the header pins of a Raspberry Pi is a screenshot from a JavaFX project
which you can find in:
Chapter_05_PiPinning > javafx-pinning-info
In one of the next chapters we will dive into JavaFX, but feel free to look around in the code
for some first insights.
This application uses this Maven library:
1 <dependency>
2 <groupId>be.webtechie</groupId>
3 <artifactId>pi-headers</artifactId>
4 <version>0.1.1</version>
5 </dependency>
Chapter 5: Raspberry Pi pinning 92
Raspberry Pi types
Models
Raspberry Pi boards are available in different models, enabling you to select the right one for your
project. Model B is most known and used as it has the most connections. If you don’t need a cabled
network connection, you can use a Model A. The Zero is the smallest one, but not applicable for
Java projects as it doesn’t have the correct processor (see “Chapter 4: Java”).
The Compute module is aimed at professional use as it needs to be integrated on a board that can be
fully adjusted to fit in a specific product. It is already used in industrial controllers and computers,
home automation, panel PCs, …
Name Description
Model A Without ethernet connector
Model B With ethernet connector
Zero Smaller size and reduced GPIO capabilities
Compute Module Pi on a 200-pin DDR2-memory-like module for integration in embedded devices
Major versions
Both Model A and B evolved and had different versions. Each version extended and improved the
boards. These were the main changes:
Chapter 5: Raspberry Pi pinning 93
Board versions
The full list of board versions with the models and major versions gives this list:
By using this board version list of the Maven dependency in combination with the JavaFX
timeline application, that we already used in “Chapter 4: Java”, you get this nice timeline
with the Raspberry Pi model history.
Chapter_04_Java > java-timeline
Chapter 5: Raspberry Pi pinning 94
Pin types
The type of header is different between the Pi board versions and contains 8, 26 or 40 pins. These
pins have different functions:
Digital GPIO
The other ones are “General-Purpose Input/Output” (GPIO) pins. These pins can be addressed with
software to act as input or output for an application. They use 3.3V, meaning an output pin will be
set to 0V (low) or 3.3V (high) and an input pin will read 0V as low and 3.3V as high.
Most of the GPIOs have an internal pull-up or pull-down resistor which can be enabled in software.
The use of this is illustrated with the use of a push-button in “Chapter 5: Pi4J > Digital input with a
button”.
Chapter 5: Raspberry Pi pinning 96
Pin functions
Certain GPIOs can be used for specific functions. The functionality is described here shortly,
while in “Chapter 7: JavaFX” and “Chapter 9: Pi4J” examples are provided to make their specific
functionalities more clear.
Name Label Description
UART Universal Asynchronous Receiver and Asynchronous serial communication protocol
Transmitter
GPCLK General Purpose Clock Output a fixed frequency
I2C Inter Integrated Circuit Synchronous serial computer bus
SPI Serial Peripheral Interface Four-wire serial bus
PWM Pulse-Width Modulation Generate analog output with a digital one
The communication between these two devices can happen in different ways:
• simplex: one direction only without a message back to confirm the receiving
• half-duplex: devices can only send or receive at once
• full-duplex: both devices can send and receive at the same time
Serial communication is done at a predefined speed which needs to be known on both sides, as both
the sender and receiver need to handle the data at the same speed. This speed is called the “baud
rate” with a value indicating the number of bits per second (bps). The most used speed is 9600 bps,
Chapter 5: Raspberry Pi pinning 97
but you can use lower (1200, 2400, 4800) or higher (19200, 38400, 57600, 115200) speeds, depending
on the speed which can be handled reliably by the device.
The Pi has two built-in UART connections to GPIOs BCM number 14 (TX) and 15 (RX). Identical to
the other GPIOs, they use 3.3V so make sure, when you connect other devices, the same voltage is
used.
It can be used to transfer (low-speed) data between boards over a short distance.
I²C needs two cables and two pins are designed for this purpose, GPIOs with BCM numbers 2 (data)
and 3 (clock).
I was going to make a JavaFX application to generate this chart, just like the one used for
the timeline images in “Chapter 4: Java”. However, to avoid the “NIH Syndrome” (see “Just
a thought: Important abbreviations”) I decided to first look for an existing solution. After a
quick search, I found an instructable by Artworker⁵⁴ in which a nice and ready to use Excel
is shared to generate the above image.
PWM can be generated with software (e.g. using timers) on all GPIO pins, but a more stable signal
can be produced with hardware functions provided on GPIOs with BCM numbers 12, 13, 18 and 19.
These are marked in the PIN table with the type “DIGITAL_AND_PWM” (yellow).
⁵⁴https://www.instructables.com/id/Make-Digital-Graphs-in-Excel/
Chapter 5: Raspberry Pi pinning 99
Header types
Depending on the type of board one or two headers are available with different GPIO functions on
the pins:
Description Headers
Original Model B 26pin header - type 1
Model A and Model B (revision 2) 26pin header - type 2 + 8pin header
Model A+, B+, Pi Zero, Pi Zero W, Pi2B, Pi3B, Pi4B 40pin header
The colors in the header and table view indicate the type of pin:
40-pin header
You can find a header visualization at the start of this chapter. That same data can be used in the
same JavaFX application to generate a table view. This is the pin list of the 40-pin header:
Chapter 5: Raspberry Pi pinning 100
The above table view threw an error while developing because JavaFX PropertyValueFactory
was unable to receive property from a class located in a different package.
This was caused by the module system which has been added in Java version 9 and only
allows modules to access other modules when permission is defined for it.
In this project this was fixed by adding the “opens” line in “module-info.java”:
1 module be.webtechie {
2 requires javafx.controls;
3 requires be.webtechie.piheaders;
4 opens be.webtechie to javafx.graphics;
5 }
8-pin header
8 pins header
Chapter 5: Raspberry Pi pinning 103
BCM number
BCM refers to the “Broadcom SOC channel” number, which is the numbering inside the chip which
is used on the Raspberry Pi.
These numbers changed between board versions as you can see in the previous tables for the 26-pin
header type 1 versus 2, and or not sequential.
WiringPi number
WiringPi⁵⁵ is developed by Gordon Henderson⁵⁶ and installed by default on the Pi when you use
Raspbian. You can easily check the version and pins with the commands “gpio -v” and “gpio readall”.
This is the result on a Pi 3B+:
⁵⁵http://wiringpi.com
⁵⁶https://twitter.com/drogon
Chapter 5: Raspberry Pi pinning 104
1 $ gpio -v
2 gpio version: 2.50
3 Copyright (c) 2012-2018 Gordon Henderson
4 This is free software with ABSOLUTELY NO WARRANTY.
5 For details type: gpio -warranty
6
7 Raspberry Pi Details:
8 Type: Pi 3B+, Revision: 03, Memory: 1024MB, Maker: Sony
9 * Device tree is enabled.
10 *--> Raspberry Pi 3 Model B Plus Rev 1.3
11 * This Raspberry Pi supports user-level GPIO access.
12
13 $ gpio readall
14 +-----+-----+---------+------+---+---Pi 3B+-+---+------+---------+-----+-----+
15 | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
16 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
17 | | | 3.3v | | | 1 || 2 | | | 5v | | |
18 | 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
19 | 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
20 | 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 0 | IN | TxD | 15 | 14 |
21 | | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 |
22 | 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 |
23 | 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | |
24 | 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 |
25 | | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 |
26 | 10 | 12 | MOSI | IN | 0 | 19 || 20 | | | 0v | | |
27 | 9 | 13 | MISO | IN | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 |
28 | 11 | 14 | SCLK | IN | 0 | 23 || 24 | 1 | IN | CE0 | 10 | 8 |
29 | | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
30 | 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
31 | 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
32 | 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 |
33 | 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | |
34 | 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 |
35 | 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 |
36 | | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 |
37 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
38 | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
39 +-----+-----+---------+------+---+---Pi 3B+-+---+------+---------+-----+-----+
As you can see “gpio readall” gives you a nice overview of the different pin numberings and
functions.
The WiringPi numbering can be a bit confusing if you don’t have an overview table. But this
Chapter 5: Raspberry Pi pinning 105
numbering has a “historical reason”. When development for the very first Raspberry Pi’s was
ongoing, only 8 pin numbers were foreseen. But when the designs further evolved and more pins
were added, the numbering in WiringPi was extended to be able to address the extra pins.
As Pi4J (see Chapter 9) uses WiringPi “under the hood”, it’s important to know this numbering
scheme is used. In the example code, the BCM number is also added to make things more clear.
Important, if you are using a Raspberry Pi 4, you will need to make sure you are on the latest
version 2.52. Because the internal wiring of the processor of this type is different compared to the
previous boards, an updated gpio is available. Check the version with “gpio -v” in the terminal and
install the new version with the following commands:
1 $ gpio -v
2 gpio version: 2.50
3 $ cd /tmp
4 $ wget https://project-downloads.drogon.net/wiringpi-latest.deb
5 $ sudo dpkg -i wiringpi-latest.deb
6 $ gpio -v
7 gpio version: 2.52
Unfortunately the maker of WiringPi announced in August 2019, he stopped further development of
this tool⁵⁷. His decision is based on the problem many open-source developers of popular tools are
facing. A lot of people use it and ask for free support or even worse, re-use and sell products using
the code without giving proper credits to the maker.
That’s the main reason this book and the README-files in the sources contain all the links of the
sites and tools used while writing this book. Without all those people who publish and share their
knowledge, creating the examples for this book would not have been possible.
⁵⁷http://wiringpi.com/wiringpi-deprecated/
Chapter 6: What is Maven?
Maven⁵⁸ is a tool to help you to manage the dependencies (external libraries) of your Java
project and build the application for testing and distribution. It works by using a predefined
structure to organize your code and to describe a project in a pom.xml (Project Object Model) file.
Based on different polls, about 50 to 60% of Java developers use Maven. There are other tools available
to do the same thing, with Gradle being the second most popular one (20 to 30%). As I’m most familiar
with Maven and it’s the most used one, we will only work with it in this book.
Next to the development tool, there is also the on-line Maven Repository⁵⁹ where you can find
a long list of versioned libraries.
Let’s take a look for example at the TilesFX library we will be using in chapter 7. Go to the
mvnrepository.com website and search for TilesFX.
If we click on the “tilesfx” link, we get the page with all the available versions of this library.
⁵⁸https://maven.apache.org/
⁵⁹https://mvnrepository.com/
Chapter 6: What is Maven? 107
By selecting the version you want to use (in most cases the latest and most recent one), you can
copy and paste the xml dependency code to add to the pom.xml file.
Also the “LED number display” JavaFX library created for ‘Chapter 8 Bits & Bytes” can be found in
the Maven Repository:
Install Maven
On Windows PC
• First install an up-to-date version of Java
• Download the ZIP from the Apache Maven website⁶⁰
• Unzip and move the directory to e.g. “C:Program Files\apache-maven”
• Right-click on “My PC” in explorer and select “Properties” > “Advanced system settings” >
“Environment variables”
• Add the location of the “Maven” > “bin” directory to the “User variables” > “Path” settings
• Click “OK” till all boxes are closed
• Sign out and in again (or restart)
• Check the version in cmd
1 $ mvn -v
2 Apache Maven 3.6.2 (40f523331...; 2019-08-27T17:06:16+02:00)
3 Maven home: C:\Program Files\apache-maven-3.6.2\bin\..
4 Java version: 11.0.4, vendor: AdoptOpenJDK, runtime:
5 C:\Program Files\AdoptOpenJDK\jdk-11.0.4.11-hotspot
6 Default locale: en_US, platform encoding: Cp1252
7 OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
On Raspberry Pi
We only need to call the “apt” program with the correct parameters from the terminal to add Maven
to our Pi:
⁶⁰https://maven.apache.org/download.cgi
Chapter 6: What is Maven? 110
1 $ mvn -v
2 Apache Maven 3.6.0
3 Maven home: /usr/share/maven
4 Java version: 13-BellSoft, vendor: BellSoft, runtime:
5 /usr/lib/jvm/bellsoft-java13-arm32-vfp-hflt
6 OS name: "linux", version: "4.19.66-v7l+", arch: "arm", family: "unix"
Chapter 6: What is Maven? 111
1 mvn archetype:generate
2 -DgroupId=be.webtechie
3 -DartifactId=java-maven-minimal
4 -DarchetypeArtifactId=maven-archetype-quickstart
5 -DinteractiveMode=false
Project structure
As you can see in the next screenshot, the created Maven project has a clear structure. The pom.xml
file is in the root directory. All code is in the directory structure src > main > java > be > webtechie
(based on the artifactId). There is also a unit test file available in src > test > java > be > webtechie.
1 <project xmlns="http://maven.apache.org/POM/4.0.0"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
4 http://maven.apache.org/maven-v4_0_0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6 <!--
7 The "project" element contains info about the layout of the document
8 and we leave it as is. The same goes for "modelVersion".
9 -->
10
11 <!--
12 Minimum required info about this project.
13 -->
14 <groupId>be.webtechie</groupId>
15 <artifactId>java-maven-minimal</artifactId>
16 <version>1.0-SNAPSHOT</version>
17
18 <!--
19 Info about the project.
20 -->
21 <name>java-maven-minimal</name>
22 <url>http://maven.apache.org</url>
23
24 <!--
25 How the application needs to be packaged for distribution by Maven.
26 -->
27 <packaging>jar</packaging>
28
29 <!--
30 Define extra dependencies needed in the application.
31 In this example the JUnit test library is added.
32 -->
33 <dependencies>
34 <dependency>
35 <groupId>junit</groupId>
⁶¹https://maven.apache.org/guides/introduction/introduction-to-the-pom.html
Chapter 6: What is Maven? 113
36 <artifactId>junit</artifactId>
37 <version>3.8.1</version>
38 <scope>test</scope>
39 </dependency>
40 </dependencies>
41 </project>
Chapter 6: What is Maven? 114
1 <build>
2 <plugins>
3 <plugin>
4 <groupId>org.apache.maven.plugins</groupId>
5 <artifactId>maven-compiler-plugin</artifactId>
6 <version>3.8.0</version>
7 <configuration>
8 <release>11</release>
9 </configuration>
10 </plugin>
11
12 <plugin>
13 <artifactId>maven-assembly-plugin</artifactId>
14 <version>2.2.1</version>
15 <configuration>
16 <descriptorRefs>
17 <descriptorRef>jar-with-dependencies</descriptorRef>
18 </descriptorRefs>
19 <archive>
20 <manifest>
21 <addClasspath>true</addClasspath>
22 <mainClass>be.webtechie.App</mainClass>
23 </manifest>
24 </archive>
25 </configuration>
26 <executions>
27 <execution>
28 <id>make-assembly</id>
29 <phase>package</phase>
30 <goals>
31 <goal>single</goal>
Chapter 6: What is Maven? 115
32 </goals>
33 </execution>
34 </executions>
35 </plugin>
36 </plugins>
37 </build>
With these plugin included in the “pom.xml”-file, we can build the application with the following
command in the terminal inside your application directory:
Don’t worry if this is not fully clear at this moment! In the GitHub sources of each example used
in this book, you can find the correct pom-file and the generated jar-file you can run on the Pi. So
you have the choice to generate the package yourself, or use the provided one. How to build and run
each example is also described in the examples.
Chapter 6: What is Maven? 116
A simple sample application to illustrate the initialization and use of log4j logging can be
found in:
Chapter_06_Maven > java-maven-logging
1 <dependency>
2 <groupId>log4j</groupId>
3 <artifactId>log4j</artifactId>
4 <version>1.2.17</version>
5 </dependency>
1 package be.webtechie;
2
3 import org.apache.log4j.ConsoleAppender;
4 import org.apache.log4j.Level;
5 import org.apache.log4j.Logger;
6 import org.apache.log4j.PatternLayout;
7 import org.apache.log4j.RollingFileAppender;
8
9 /**
10 * Hello world!
11 *
12 */
13 public class App {
14 private static Logger logger = Logger.getLogger(App.class);
15
16 public static void main( String[] args ) {
17 Logger.getRootLogger().getLoggerRepository().resetConfiguration();
18 initLog();
Chapter 6: What is Maven? 117
19
20 logger.debug("Debug message");
21 logger.info("Info message");
22 logger.warn("Warn message");
23 logger.error("Error message");
24 }
25
26 private static void initLog() {
27 PatternLayout logPattern =
28 new PatternLayout("%d{yyyyMMdd HH:mm:ss,SSS} | %-5p | [%c{1}] | %m%n");
29
30 // Log to the console, similar to System.out
31 ConsoleAppender console = new ConsoleAppender();
32 console.setName("ConsoleLogger");
33 console.setLayout(logPattern);
34 console.setThreshold(Level.DEBUG);
35 console.activateOptions();
36 Logger.getRootLogger().addAppender(console);
37
38 // Log to a file to store it for later reference,
39 // creating max 5 files of 10MB
40 RollingFileAppender file = new RollingFileAppender();
41 file.setName("FileLogger");
42 file.setFile("logs/app.log");
43 file.setLayout(logPattern);
44 file.setThreshold(Level.INFO);
45 file.setAppend(true);
46 file.activateOptions();
47 file.setMaxFileSize("10MB");
48 file.setMaxBackupIndex(5);
49 Logger.getRootLogger().addAppender(file);
50 }
51 }
Please check “Java Logging” on jenkov.com⁶² for other and more detailed ways to configure the
logger. Full log4j documentation is available on logging.apache.org/log4j/1.2/apidocs⁶³.
When running this example application, the output will look like this:
⁶²http://tutorials.jenkov.com/java-logging/index.html
⁶³https://logging.apache.org/log4j/1.2/apidocs/index.html
Chapter 6: What is Maven? 118
If you run an application in IntelliJ IDEA with this logging configuration and the
Grep Console plugin⁶⁴, the warn and error lines will be highlighted, which makes it
very easy to debug your code!
⁶⁴https://plugins.jetbrains.com/plugin/7125-grep-console
Just a thought: Abbreviations
As a developer, there are some “important” abbreviations you need to know.
YAGNI
“You Aren’t Gonna Need It” is used to point out the fact you don’t need to add code until you
need it. Sometimes it feels right to add some additional methods which could one day be useful.
But as long as you didn’t finish and test the code you need, you cannot be sure what additional code
you’ll need in the future. And it doesn’t make sense to write code which may never be used at
all.
KISS principle
At work (only?) I mention from time to time I love to KISS. But at work that means “Keep It Simple,
Stupid”. The goal of the KISS principle is to keep your code as simple as possible. Breaking
complex methods in multiple smaller ones, is one of the easiest ways to achieve this. If your method
has a name like “doThisAndThisAndReturnThat”, you already should notice you could break it into
three smaller ones.
POGE
Always keep the Principle Of Good Enough in mind when you develop software. Users will go for
anything which fulfills their needs, even if more advanced solutions are available. It’s better to go
for a quick good solution, than to keep working towards perfection, that unreachable goal… At
my CoderDojo club a boy is already working on the same Minecraft project for years, and it never
gets finished as he keeps adding new features. That same problem exists in many software teams.
Deliver fast, fail fast, improve even faster and never forget: “Perfect is the enemy of good“.
NIH
Engineers tend to suffer the “Not Invented Here” Syndrome. They keep reinventing the wheel while
they often could benefit by adopting existing solutions. Often this syndrome is caused by the idea it
is cheaper to do something yourself instead of paying for a license or hiring someone with experience
in the matter. As a good developer, if you need to de something new, your first step should be to
investigate if there are existing frameworks, methodologies, program languages… which can
solve your problem.
DRY
The “Don’t repeat yourself” principle, aims to divide your application into small blocks with a
single responsibility. Each block may only appear once in your system. Tools like SonarLint which
integrate with your IDE, will alert you if you have identical or similar code at multiple places. But
you don’t always need a tool, if you feel you are repeating yourself, take a step back and look at how
you can improve and simplify your code. If you aren’t following this approach, you end up with a
“WET solution” aka “Waste Everyone’s Time”.
Just a thought: Abbreviations 120
TDD
“Test Driven Development”ʰ is a way of coding, in which you first write the minimal test for a
new feature in your application. As soon as your test succeeds you can refactor and improve your
implementation. If you need more functionality, you first extend the test which has to turn green
by adding the required code, and all previous tests should stay green.
Other DD-principles are “Behavior Driven Development”ⁱ and “Domain Driven Design”ʲ.
BDD focusses on creating applications by a team in which each member has a different role
(developer, tester, manager…) and fully understands the functionality to be implemented.
DDD is driven by a “domain expert” who can explain how the system should work which needs
to be implemented and keeps an overview of the full development. Different subsystems can be
developed but share the same “domain”. For instance, if you would design a software system for a
shop you would have a database that stores the data, next to a program where clients and orders
can be managed by two teams but share some functions for after-sales support. The domain expert
has an overview of all the use cases and can guide the development team in the best approach.
While most teams aim to use a healthy mix of these and other principles, still “Deadline Driven
Development” is the real-world approach in a lot of companies…
RTFM
“Read The Fucking Manual” is often used by a developer who gets frustrated by users asking the
same question over and over again. But in my opinion, the user is always right. This means, if they
keep asking how something works, you probably didn’t make it easy enough or the user is using it
differently than what you assumed would happen.
That’s why you need to “fail fast and often”, meaning you need to involve the end-user in your
development process as soon as possible so they can start using or testing it and give you feedback.
So next time you want to use “RTFM”, listen carefully to the question and what the user wants to
do and why he doesn’t succeed…
https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
https://en.wikipedia.org/wiki/KISS_principle
https://en.wikipedia.org/wiki/Principle_of_good_enough
https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good
https://en.wikipedia.org/wiki/Not_invented_here
https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
https://www.sonarlint.org/
ʰhttps://en.wikipedia.org/wiki/Test-driven_development
ⁱhttps://en.wikipedia.org/wiki/Behavior-driven_development
ʲhttps://en.wikipedia.org/wiki/Domain-driven_design
https://en.wikipedia.org/wiki/RTFM
Chapter 7: About JavaFX
From the Oracle site: “JavaFX is a set of graphics and media packages that enables developers to
design, create, test, debug, and deploy rich client applications that operate consistently across diverse
platforms.”
JavaFX was created by Sun Microsystems, later became part of Oracle Corporation and is now an
open-source project on openjfx.io⁶⁵ for which commercial support is available via GluonHQ⁶⁶.
The sources are available on GitHub⁶⁷.
JavaFX allows you to quickly build a user interface while using the language and tools you
already know as a Java developer. This can be styled with a CSS syntax and is very flexible and
extendable, or you can draw things with code as I’ve done in “Chapter 03: Java” for the timelines.
There are a lot of projects going on to make it very developer-friendly to be able to publish your
application easily to different operating systems and platforms. Keep an eye on the news messages
by GluonHQ and GraalVM⁶⁸ who are working together on these solutions.
⁶⁵https://openjfx.io/
⁶⁶https://gluonhq.com/
⁶⁷https://github.com/openjdk/jfx
⁶⁸https://www.graalvm.org/
Chapter 7: About JavaFX 122
History
Timeline of JavaFX
JavaFX was initially (version 1) a platform to develop Rich Internet Applications (RIA) to make it
easy to create web-based interfaces with a scripting language.
After Oracle acquired Java and JavaFX from Sun Microsystems in 2009, it announced a new major
version 2 in 2010. This was released in October 2011 and changed from a scripting language to a
Java API.
The version numbering jumped to 8 when Java 8 itself introduced a lot of new APIs and language
enhancements and JavaFX got improved to be in line with all these changes.
Since version 11 the JavaFX module moved out of the JDK and GluonHQ is maintaining openJFX
with the support of many contributors (also still Oracle). Just like the new 6-month release cycle of
Java, JavaFX development speed has increased pushing new features forward.
Chapter 7: About JavaFX 123
In your opinion, what is the most important change within the Java/JavaFX ecosystem in recent
years?
The decoupling of the JDK was an important change with a big impact. We knew this would
shock several developers, but with the JDK and the ecosystem going modular, we had to do this
with OpenJFX as well. We are now in pretty smooth waters, where the majority of the ecosystem
embraced the modular approach and is using existing, familiar tools like Maven or Gradle to create
JavaFX applications. For those developers and companies that prefer a separate SDK, we still offer
that as well.
Why is now the perfect time to learn Java?
With Java, you learn a language that doesn’t lock you in a particular market, area, or even language
itself. Many languages are using the Java VM, and Java is used in a wide range of domains, in open-
source and commercial software.
It is very mature, stable, and still very innovative, e.g. with the 6-month release cycles.
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
Alarm system for home, including AI and face recognition.
Automotive interface.
https://twitter.com/johanvos
https://gluonhq.com//
https://www.graalvm.org/
https://github.com/gluonhq/substrate
Chapter 7: About JavaFX 125
TilesFX
This great library is developed by Gerrit Grunwald⁷¹ and provides tiles to build dashboards. Check
his blog⁷² for many more JavaFX examples!
You can find the sources on GitHub⁷³ and it is available as a Maven dependency⁷⁴.
FXRibbon
Inspired by the Microsoft Ribbon, this library developed by Pedro Duque⁷⁵, provides a similar
component in JavaFX. You can use this control to simplify the UI of applications with a significant
number of actions.
⁶⁹https://twitter.com/mhrimaz
⁷⁰https://github.com/mhrimaz/AwesomeJavaFX
⁷¹https://twitter.com/hansolo_
⁷²https://harmoniccode.blogspot.com/
⁷³https://github.com/HanSolo/tilesfx
⁷⁴https://mvnrepository.com/artifact/eu.hansolo/tilesfx
⁷⁵https://twitter.com/P_Duke
Chapter 7: About JavaFX 126
You can find the sources on GitHub⁷⁶ and it is available as a Maven dependency⁷⁷.
ControlsFX
Project by Jonathan Giles⁷⁸.
You can find the sources on GitHub⁷⁹ and it is available as a Maven dependency⁸⁰.
PickerFX
Project by one of those other JavaFX heroes Dirk Lemmermann⁸¹. He has many others, so check out
his full GitHub repo!
⁷⁶https://github.com/dukke/FXRibbon
⁷⁷https://mvnrepository.com/artifact/com.pixelduke/FXRibbon
⁷⁸https://twitter.com/JonathanGiles
⁷⁹https://github.com/controlsfx/controlsfx
⁸⁰https://mvnrepository.com/artifact/org.controlsfx/controlsfx
⁸¹https://twitter.com/dlemmermann
Chapter 7: About JavaFX 127
You can find the sources on GitHub⁸² and it is available as a Maven dependency⁸³. Make sure to also
check his blog with more awesome JavaFX stuff like JMetro⁸⁴!
The last step will take a while, but finally, you should have this in the log:
1 [INFO] ------------------------------------------------------------------------
2 [INFO] Reactor Summary for Maven Archetypes for JavaFX 0.0.2-SNAPSHOT:
3 [INFO]
4 [INFO] Maven Archetypes for JavaFX ........................ SUCCESS [ 1.883 s]
5 [INFO] Simple JavaFX Maven Archetype ...................... SUCCESS [ 8.548 s]
6 [INFO] FXML JavaFX Maven Archetype ........................ SUCCESS [ 0.304 s]
7 [INFO] ------------------------------------------------------------------------
8 [INFO] BUILD SUCCESS
9 [INFO] ------------------------------------------------------------------------
1 $ mvn archetype:generate
2 -DarchetypeGroupId=org.openjfx
3 -DarchetypeArtifactId=javafx-archetype-simple
4 -DarchetypeVersion=0.0.1
5 -DgroupId=be.webtechie
6 -DartifactId=javafx-minimal
7 -Dversion=0.0.1
You can define the values for groupId, artifactId and version yourself, the given values above are
just examples.
After running the above script a new Java Maven project is created for you with a pom-file and the
first Java source files.
The project created with the above command is available in the sources in the directory:
Chapter_07_JavaFX > javafx-minimal
1 $ java -version
2 openjdk version "11.0.4" 2019-07-16
3 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.4+11)
4 OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.4+11, mixed mode)
You can start the application with the “Run|Debug” popup from within Visual Studio Code.
Chapter 7: About JavaFX 131
Or you can do the same with the Maven command “mvn javafx:run”:
In the application, the version of your installed Java JDK and JavaFX are displayed.
1 pi@raspberrypi:~ $ cd /home/pi/javafx/
2 pi@raspberrypi:~/javafx $ ls -l
3 total 8
4 -rw-r--r-- 1 pi pi 1497 Feb 18 20:00 pom.xml
5 drwxr-xr-x 3 pi pi 4096 Feb 18 20:00 src
6 pi@raspberrypi:~/javafx $ mvn javafx:run
Chapter 7: About JavaFX 133
To test if we connected the LED in the correct direction, we can plug in a cable between a 3.3V pin
and GPIO22. If the LED doesn’t turn on, we need to swap it.
Chapter 7: About JavaFX 135
Wiring on a breadboard
To test the connections we will use “gpio” via the terminal. This program is part of Raspbian, so we
don’t need to install anything to be able to do this. Make sure you are on the latest gpio-version if
you are using a Raspberry Pi 4, see Chapter 5 > WiringPi number.
Turn LED on GPIO22 on (1) and off (0):
1 $ gpio mode 5 in
2 $ gpio read 5
3 1
1 $ nano HelloGpio.java
2
3 public class HelloGpio {
4 public static void main (String[] args) {
5 System.out.println("Hello Gpio");
6
7 try {
8 Runtime.getRuntime().exec("gpio mode 3 out");
9
10 var on = true;
11
12 for (var loopCounter = 0; loopCounter < 10; loopCounter++) {
13 System.out.println("Changing LED to " + (on ? "on" : "off"));
14 Runtime.getRuntime().exec("gpio write 3 " + (on ? "1" : "0"));
15
16 on = !on;
17
18 Thread.sleep(500);
19 }
20 } catch (Exception ex) {
21 System.err.println("Exception from Runtime: "
22 + ex.getMessage());
23 }
24 }
25 }
In this example code, we configure pin 3 to be and output-pin and toggle it 10 times between “on”
and “off”, with an interval of 500 milliseconds. Java requires us to catch possible exceptions, so that’s
why there is some extra try/catch code.
Make sure you are still in the same directory and run this code without compiling (because we use
Java 11 or a newer version) with the following result:
Chapter 7: About JavaFX 137
1 $ ls -l
2 HelloGpio.java
3
4 $ java HelloGpio.java
5 Hello Gpio
6 Changing LED to on
7 Changing LED to off
8 Changing LED to on
9 ...
The application will use the TilesFX libraries to make a fancy dashboard next to the already used
JavaFX library. We need to add the TilesFX dependency in the pom.xml file so our IDE will download
it during development and we can call the methods of it.
Go to the Maven repository website⁸⁵ and search for TilesFX.
When you click through you can select the version and on its page, you will find the dependency
to be added to the pom.xml file, where the javafx-controls dependency is already included. We also
need to add the javafx-web dependency as this is used by TilesFX.
⁸⁵https://mvnrepository.com/
Chapter 7: About JavaFX 138
While we are working in the pom.xml file, we also change the artifactId as we copied this project
from the javafx-minimal application and we add the build-plugins as described in “Chapter 6:
Maven”.
1 ...
2 <artifactId>javafx-dashboard</artifactId>
3 ...
4 <dependencies>
5 <dependency>
6 <groupId>org.openjfx</groupId>
7 <artifactId>javafx-controls</artifactId>
8 <version>11.0.2</version>
9 </dependency>
10 <dependency>
11 <groupId>org.openjfx</groupId>
12 <artifactId>javafx-web</artifactId>
13 <version>11.0.2</version>
14 </dependency>
15 <dependency>
16 <groupId>eu.hansolo</groupId>
17 <artifactId>tilesfx</artifactId>
18 <version>11.13</version>
19 </dependency>
20 </dependencies>
21
22 <build>
23 <plugins>
24 <plugin>
25 <groupId>org.apache.maven.plugins</groupId>
26 <artifactId>maven-compiler-plugin</artifactId>
27 <version>3.8.0</version>
28 <configuration>
29 <release>11</release>
30 </configuration>
31 </plugin>
32
33 <plugin>
34 <artifactId>maven-assembly-plugin</artifactId>
35 <version>2.2.1</version>
36 ...
37 </plugin>
38 </plugins>
39 </build>
Chapter 7: About JavaFX 139
40 ...
In HelloGpio.java we were able to turn an LED on and off with a small piece of code. But to be
able to handle exceptions and read the state of a GPIO, we need some more code. We create a new
class “Gpio.java”. This will use the “gpio” commands we used before in the terminal, but controlled
with Java. This is just a first “quick-win” approach as in chapter 9 we will start using Pi4J which
provides a better approach and many other methods, but at this moment we want to take a code-only
approach.
These are the last examples where the full code is documented within this book. Look into
the GitHub sources of each example including package names and imports.
1 package be.webtechie;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7
8 /**
9 * Change a pin state using WiringPi and command line calls
10 * http://wiringpi.com/the-gpio-utility/
11 */
12 public class Gpio {
13
14 }
We need one big method to run the gpio commands and handle the result. E.g. if we run “gpio read
5” we want to know if “1” or “0” is returned by gpio. We call this the “execute” method. It is a private
static method because it will only be used by other static methods inside Gpio.java. The return of
this method is a String, so we can handle the value depending on the type of result we are expecting.
To avoid memory leaks where Java blocks memory which is no longer needed, the closing of the
stream and reader is done in the finally block which gets called even if an error occurs.
Chapter 7: About JavaFX 140
1 /**
2 * Execute the given command, this is called by the public methods.
3 *
4 * @param cmd String command to be executed.
5 */
6 private static String execute(String cmd) {
7 Process p = null;
8 InputStream error = null;
9 BufferedReader input = null;
10
11 try {
12 // Get a process to be able to do native calls on the operating system.
13 // You can compare this to opening a terminal window and running a command.
14 p = Runtime.getRuntime().exec(cmd);
15
16 // Get the error stream of the process and print it
17 // so we will now if something goes wrong.
18 error = p.getErrorStream();
19 for (int i = 0; i < error.available(); i++) {
20 System.out.println("" + error.read());
21 }
22
23 // Get the output stream, this is the result of the command we give.
24 String line;
25 StringBuilder output = new StringBuilder();
26 input = new BufferedReader(new InputStreamReader(p.getInputStream()));
27 while ((line = input.readLine()) != null) {
28 output.append(line);
29 }
30 input.close();
31
32 System.out.println(cmd);
33
34 // Return the result of the command.
35 return output.toString();
36 } catch (IOException e) {
37 System.err.println(e.getMessage());
38
39 return "";
40 } finally {
41 if (p != null) {
42 p.destroy();
43 }
Chapter 7: About JavaFX 141
44
45 if (error != null) {
46 try {
47 error.close();
48 } catch (IOException ex) {
49 System.err.println("Error while closing the error stream");
50 }
51 }
52
53 if (input != null) {
54 try {
55 input.close();
56 } catch (IOException ex) {
57 System.err.println("Error while closing the input stream");
58 }
59 }
60 }
61 }
By using the “static” keyword we tell Java this method can be called without the need to
create an instance of the class.
In short, we will be able to use this method from another class like this:
1 Gpio.initiatePin(5, "out");
Without the static keyword we need two lines as we need to create an instance of the class
first:
In this case, we can use static methods as we don’t need to define values used in all the
methods of Gpio, or don’t need Gpio to do stuff first, before using one of its methods. In the
next class, we will make “FxSreen”, that works differently.
Now let’s use this “execute” to initiate a pin. For this, we need to set the mode and don’t need to
handle the return. Again we define this as a static method.
Chapter 7: About JavaFX 142
1 /**
2 * Initialize the pin so it can be toggled later.
3 *
4 * @param pin The pin number according to the WiringPi numbering scheme
5 */
6 public static void initiatePin(final int pin, final String mode) {
7 execute("gpio mode " + pin + " " + mode);
8 }
Setting a pin to high or low also can be done without handling the return.
1 /**
2 * Set the state of the pin high or low.
3 *
4 * @param pin The pin number according to the WiringPi numbering scheme
5 * @param on True or False
6 */
7 public static void setPinState(final int pin, final boolean on) {
8 execute("gpio write " + pin + (on ? " 1" : " 0"));
9 }
Reading a pin state needs some extra handling, as the result needs to be parsed to return a boolean
for true (=high) or false (=low).
1 /**
2 * Get the state of the pin.
3 *
4 * @param pin The pin number according to the WiringPi numbering scheme
5 * @return Flag if the pin is high (1 = true) or low (0 = false)
6 */
7 public static boolean getPinState(final int pin) {
8 final String result = execute("gpio read " + pin);
9
10 System.out.println("Getting pin state of " + pin + ", result: " + result);
11
12 return result.equals("1");
13 }
TilesFX dashboard
When the application starts, we want it to load a dashboard screen. Thanks to TilesFX this can be
created quite easily. We create a new class “FxScreen.java” with the following code.
Here we won’t be using static methods, as we want to initialize a lot of stuff when we use the class.
1 package be.webtechie;
2
3 import eu.hansolo.tilesfx.Tile.SkinType;
4 import eu.hansolo.tilesfx.TileBuilder;
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.Locale;
8 import java.util.Random;
9
10 import javafx.application.Platform;
11 import javafx.geometry.Pos;
12 import javafx.scene.chart.XYChart;
13 import javafx.scene.control.Button;
14 import javafx.scene.layout.HBox;
15 import javafx.scene.layout.VBox;
16
17 /**
18 * Helper class to create our graphical user interface.
19 */
20 public class FxScreen extends HBox {
Chapter 7: About JavaFX 144
21
22 }
We also need some variables we will use in the methods later, so let’s add them to the class.
Now let’s add the constructor. This one gets called if you create a new instance of this class from
another one. Later in the main class we will call this with:
1 new FxScreen();
Which will call this constructor and here we initialize the variables we will use later.
Chapter 7: About JavaFX 145
1 /**
2 * Constructor.
3 */
4 public FxScreen() {
5 // Initialize the pins
6 Gpio.initiatePin(PIN_LED, "out");
7 Gpio.initiatePin(PIN_BUTTON, "in");
8
9 // Setup the line chart data series
10 this.seriesTemperatureInside = new XYChart.Series();
11 this.seriesTemperatureInside.setName("Inside temperature");
12
13 this.seriesTemperatureOutside = new XYChart.Series();
14 this.seriesTemperatureOutside.setName("Outside temperature");
15
16 this.seriesButton = new XYChart.Series();
17 this.seriesButton.setName("Button pressed");
18
19 // Start thread which will generated dummy data
20 this.startDemoData();
21
22 // Start thread which read the button state
23 this.startButtonRead();
24
25 // Build the screen
26 this.buildScreen();
27 }
A good coding practice, is to keep your methods short and readable. That’s why at the end we are
calling other methods to start two threads and build up the screen. The first thread generates random
temperature values every 2,5” to fill in one of the charts.
1 /**
2 * Thread to generate random test temperatures.
3 */
4 private void startDemoData() {
5 Thread t = new Thread(() -> {
6 while (running) {
7 var timeStamp = new SimpleDateFormat("HH.mm.ss").format(new Date());
8 this.seriesTemperatureInside.getData()
9 .add(new XYChart.Data(timeStamp, this.randomNumber(17,25)));
10 this.seriesTemperatureOutside.getData()
11 .add(new XYChart.Data(timeStamp, this.randomNumber(-10,30)));
Chapter 7: About JavaFX 146
12
13 try {
14 Thread.sleep(2500);
15 } catch (InterruptedException ex) {
16 System.err.println("Data thread got interrupted");
17 }
18 }
19 });
20
21 t.start();
22 }
23
24 /**
25 * Generate random number between the given limits.
26 *
27 * @param min
28 * @param max
29 * @return
30 */
31 private int randomNumber(int min, int max) {
32 Random rand = new Random();
33 return rand.nextInt((max - min) + 1) + min;
34 }
The second thread reads the button state every half second and updates the data for the second chart
if the button state has changed. In the Pi4J chapter you can find code to achieve this with an event
handler if you need immediate feedback on input changes instead of a check based on an interval
as we use here.
1 /**
2 * Thread to read the button state.
3 */
4 private void startButtonRead() {
5 Thread t = new Thread(() -> {
6 while (running) {
7 var buttonPressed = Gpio.getPinState(PIN_BUTTON);
8
9 if (buttonIsPressed != buttonPressed) {
10 buttonIsPressed = buttonPressed;
11
12 var timeStamp = new SimpleDateFormat("HH.mm.ss")
13 .format(new Date());
14 this.seriesButton.getData()
Chapter 7: About JavaFX 147
The only remaining big block is the creation of the screen itself. As we are using TilesFX, this is
done by defining a bunch of different tiles. We want to have them in two different VBox’s and these
are added to the overall HBox.
1 /**
2 * Build the screen.
3 */
4 private void buildScreen() {
5 // Get the Java version info
6 final String javaVersion = System.getProperty("java.version");
7 final String javaFxVersion = System.getProperty("javafx.version");
8
9 // Define our local setting (used by the clock)
10 var locale = new Locale("nl", "be");
11
12 // Tile with the Java info
13 var textTile = TileBuilder.create()
14 .skinType(SkinType.TEXT)
15 .prefSize(250, 200)
16 .title("Version info")
17 .description("Java: " + javaVersion + "\nJavaFX: " + javaFxVersion)
18 .descriptionAlignment(Pos.TOP_CENTER)
19 .textVisible(true)
20 .build();
21
22 ...
23
24 // Tile with a switch button to turn our LED on or off
25 var ledSwitchTile = TileBuilder.create()
Chapter 7: About JavaFX 148
26 .skinType(SkinType.SWITCH)
27 .prefSize(250, 200)
28 .title("Gpio " + PIN_LED)
29 .roundedCorners(false)
30 .build();
31
32 ledSwitchTile.setOnSwitchReleased(e -> Gpio
33 .setPinState(PIN_LED, ledSwitchTile.isActive()));
34
35 // Tile with an exit button to end the application
36 var exitButton = new Button("Exit");
37 exitButton.setOnAction(e -> endApplication());
38
39 var exitTile = TileBuilder.create()
40 .skinType(SkinType.CUSTOM)
41 .prefSize(250, 200)
42 .title("Quit the application")
43 .graphic(exitButton)
44 .roundedCorners(false)
45 .build();
46
47 ...
48
49 // Line chart example which will get the button state from a thread
50 var buttonLineChartTile = TileBuilder.create()
51 .skinType(SkinType.SMOOTHED_CHART)
52 .prefSize(550, 400)
53 .title("Button GPIO state")
54 .smoothing(false)
55 .series(this.seriesButton)
56 .build();
57
58 var tilesColumn1 = new VBox(textTile, clockTile, ledSwitchTile, exitTile);
59 tilesColumn1.setMinWidth(250);
60 tilesColumn1.setSpacing(5);
61
62 var tilesColumn2 = new VBox(tempartureLineChartTile, buttonLineChartTile);
63 tilesColumn2.setSpacing(5);
64
65 this.getChildren().add(tilesColumn1);
66 this.getChildren().add(tilesColumn2);
67 }
68
Chapter 7: About JavaFX 149
69 /**
70 * Stop the threads and close the application.
71 */
72 private void endApplication() {
73 this.running = false;
74
75 Platform.exit();
76 }
Start methods
To let the application start with the FxScreen.java we need to change the Main.java file which was
part of javafx-minimal so it looks like this. “Platform.setImplicitExit(true);” is also added to make
sure the application shuts down nicely.
1 package be.webtechie;
2
3 import javafx.application.Application;
4 import javafx.scene.Scene;
5 import javafx.stage.Stage;
6
7 /**
8 * JavaFX App
9 */
10 public class App extends Application {
11
12 @Override
13 public void start(Stage stage) {
14 Platform.setImplicitExit(true);
15
16 var scene = new Scene(new FxScreen(), 640, 480);
17 stage.setScene(scene);
18 stage.show();
19
20 // Make sure the application quits completely on close
21 stage.setOnCloseRequest(t -> {
22 Platform.exit();
23 System.exit(0);
24 });
25 }
26
27 public static void main(String[] args) {
28 launch();
Chapter 7: About JavaFX 150
29 }
30 }
Update module-info.java
Last small step! Add the TilesFx dependency in this file so it looks like this:
1 module be.webtechie {
2 requires javafx.controls;
3 requires eu.hansolo.tilesfx;
4 exports be.webtechie;
5 }
By using Maven and pom.xml we can build our application in the terminal of our IDE.
With “mvn clean package” the Java-files are converted to byte code class-files in the “target”
directory of our project. The same process will also collect the compiled code into a jar-file and add
the dependencies in “javafx-dashboard-0.0.1-jar-with-dependencies.jar” inside that target directory.
This jar contains our full program and dependencies, so is about 65MB in size. This would not be
ideal when we want to distribute our application, but is not an issue in our case, as we can just copy
the file to the Pi through our local network if we are developing on PC.
As the last step, we need to put the file “javafx-dashboard-0.0.1-jar-with-dependencies.jar” from the
GitHub sources, or from the PC where you have built it yourself, on the Pi with SSH (see “Chapter
2: Tools > MobaXterm”). Or you build the jar on the Pi itself if you installed Maven on it.
Open the terminal, and go to the directory where the jar-file is located. Starting it is very easy when
the Libarica JDK which includes JavaFX in installed as described in “Chapter 4: Java”:
First, some logging will be shown on the screen and a bit later the FX-screen is opened. The
temperature chart will get a new random value every 2,5”.
Chapter 7: About JavaFX 153
The LED can be toggled with the switch button on the screen in one of the tiles.
The lower chart will get a new value every half second when the button is toggled.
Conclusion
And that’s it, our very first project using Java, JavaFX and the GPIOs!
Check the TilesFX documentation and go crazy with your own version of the dashboard screen…
Chapter 7: About JavaFX 154
1. Upload your jar with the application to the Pi, for example, in the directory “/home/pi/java-
apps/”
2. Create a text file, for example, “start-script” and add the two lines to start the jar.
1 $ nano /home/pi/start-script
2
3 #! /usr/bin/bash
4 java -jar /home/pi/java-apps/my-app.jar
1 $ bash /home/pi/start-script
4. Create a new file “startup.desktop” in “/etc/xdg/autostart/” to execute the script you created when
the Pi starts.
Disable screensaver
When you build a dashboard-like application or, for example, a home automation interface, you
maybe want to disable the screensaver so the screen is never put off. By default, there is no easy
way to do this in Raspbian OS, but we can fix this easily by installing “xscreensaver”.
After running this command, you have an extra program in “Preferences” with many options where
you also can disable the screensaver completely.
Relay board
1 $ sudo raspi-config
⁸⁶https://www.amazon.com/gp/product/B07Q2P9D7K/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
⁸⁷https://wiki.52pi.com/index.php/DockerPi_4_Channel_Relay_SKU:_EP-0099
Chapter 7: About JavaFX 157
After it is enabled we can check which devices are detected. In this case, with two stacked boards
you see addresses 0x10 and 0x11 are in use.
1 $ i2cdetect -y 1
2 0 1 2 3 4 5 6 7 8 9 a b c d e f
3 00: -- -- -- -- -- -- -- -- -- -- -- -- --
4 10: 10 11 -- -- -- -- -- -- -- -- -- -- -- -- -- --
5 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
6 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
7 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
8 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
9 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10 70: -- -- -- -- -- -- -- --
We can check the relay state with “i2cget -y 1 ADDRESS RELAY” and toggle each relay in the
terminal with the command “i2cset -y 1 ADDRESS RELAY STATE” where the state is 0x00 for off
and 0xff for on.
The code is separated in different small classes to make it easy to understand and extend.
Please check the sources for the full code and structure. Check the pom.xml file for the
correct dependencies and build plugins.
Chapter_07_JavaFX > javafx-i2c-relay
Chapter 7: About JavaFX 158
To make it easy to define which boards are available and which relay we want to toggle in the
application, three different enum classes are used.
The first one defines which boards are used. As you can stack four of them, but this example only
uses two, those are the ones defined here with their address as configured with the dip switches.
Each board has four relays, with each having a byte defining their channel.
And finally, each relay has two states: on and off defined by a byte value.
Chapter 7: About JavaFX 159
I²C controller
To toggle a relay, we’ll be using the same commands as we used before in the terminal, e.g. “i2cset
-y 1 0x10 0x01 0xff”.
Let’s implement this in the class RelayController.java. We’ll provide two methods to either toggle
one relay on a specific board, or a list of relays on a list of boards.
1 /**
2 * Controller to set the relay states on different boards.
3 */
4 public class RelayController {
5 /**
6 * Set the state of all the relays on the boards.
7 *
8 * @param boards List of Enum Board
9 * @param relays List of Enum Relay
10 * @param state Enum State
11 */
12 public static void setRelays(List<Board> boards, List<Relay> relays,
13 State state) {
14 for (Board board : boards) {
15 for (Relay relay : relays) {
16 setRelay(board, relay, state);
17 }
18 }
19 }
20
Chapter 7: About JavaFX 160
21 /**
22 * Set the state of the relay on the board.
23 *
24 * @param board Enum Board
25 * @param relay Enum Relay
26 * @param state Enum State
27 */
28 public static void setRelay(Board board, Relay relay, State state) {
29 String cmd = "i2cset -y 1"
30 + " " + String.format("0x%02X", board.getAddress())
31 + " " + String.format("0x%02X", relay.getChannel())
32 + " " + String.format("0x%02X", state.getValue());
33
34 execute(cmd);
35
36 System.out.println(relay + " on " + board + " set to " + state
37 + " with command: " + cmd);
38 }
39
40 private static void execute(String cmd) {
41 // Same as used in the JavaFX dashboard application.
42 }
43 }
The user interface contains eight ControlsFX ToggleSwitches which could be created eight times.
But as “a good programmer, is a lazy programmer”, we use other methods to avoid duplicating the
same code eight times.
1 /**
2 * Builder for a screen with two rows with four toggle switches.
3 */
4 public class ToggleSwitchScreen extends VBox {
5 public ToggleSwitchScreen() {
6 this.setSpacing(25);
7 this.setPadding(new Insets(25));
8
9 this.getChildren().add(this.createRow(Board.BOARD_1, 0));
10 this.getChildren().add(this.createRow(Board.BOARD_2, 4));
11
12 System.out.println("Toggle switch screen created");
13 }
Chapter 7: About JavaFX 161
14
15 /**
16 * Create a row with four toggle switches for the given board.
17 *
18 * @param board The board to be controlled
19 * @param offset Offset for the number showed in the label
20 * @return The created HBox
21 */
22 private HBox createRow(Board board, int offset) {
23 HBox row = new HBox();
24 row.setSpacing(25);
25
26 row.getChildren().add(this.createRelayToggleSwitch(
27 "Relay " + (offset + 1),
28 board, Relay.RELAY_1));
29 row.getChildren().add(this.createRelayToggleSwitch(
30 "Relay " + (offset + 2),
31 board, Relay.RELAY_2));
32 row.getChildren().add(this.createRelayToggleSwitch(
33 "Relay " + (offset + 3),
34 board, Relay.RELAY_3));
35 row.getChildren().add(this.createRelayToggleSwitch(
36 "Relay " + (offset + 4),
37 board, Relay.RELAY_4));
38
39 return row;
40 }
41
42 /**
43 * Create a ToggleSwitch which will call the RelayController on change.
44 *
45 * @param label Label for the toggle switch
46 * @param board The board to be controlled
47 * @param relay The relay on the board to be controlled
48 * @return The created ToggleSwitch
49 */
50 private ToggleSwitch createRelayToggleSwitch(String label,
51 Board board, Relay relay) {
52 ToggleSwitch toggleSwitch = new ToggleSwitch();
53 toggleSwitch.setText(label);
54 toggleSwitch.selectedProperty()
55 .addListener((observable, oldValue, selected) ->
56 RelayController.setRelay(board, relay,
Chapter 7: About JavaFX 162
The main class could be very small, but here we added some additional code to make sure all relays
are off when the application starts.
On the board, an LED indicates the enabled relays which makes it very easy to debug the link
between the addresses you use in your application, and the toggled relays on the board.
1 $ mvn archetype:generate
2 -DarchetypeGroupId=org.openjfx
3 -DarchetypeArtifactId=javafx-archetype-fxml
4 -DarchetypeVersion=0.0.1
5 -DgroupId=be.webtechie
6 -DartifactId=javafx-fxml-minimal
7 -Dversion=0.0.1
This script to create the JavaFX FXML start project is available in:
Chapter_07_JavaFX > scripts > gluonhq_create_empty_javafx_fxml_project.sh
Or you can immediately download the generated project from:
Chapter_07_JavaFX > javafx-minimal-fxml
When you open this project in the IDE you’ll see that the visual part is in the resources-directory,
while the logic is in the java-directory as controllers.
Chapter 7: About JavaFX 165
Starting the application shows you a little box in which you can switch between two views.
As you can see in the project structure each view has an FXML file, for instance for the primary
view:
16 <padding>
17 <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
18 </padding>
19 </VBox>
And for each FXML-file a controller which handles the actions “#switchToSecondary” and “#switch-
ToPrimary”:
and
Such an approach is ideal when you are working on a bigger application where the visual work is
done by different team members than the ones who do the implementation work. They both need
to agree on the calls to be made, but the work can be handled separately.
Scene Builder
Scene Builder⁸⁸ is a tool to help you build JavaFX user interfaces. It can read FXML files and will
show you both the visual result as the properties you can define for each element.
Let’s, for instance, open the “primary.fxml” file from the generated start application. As you can see
all the available components are listed on the left, and the properties of the selected component on
the right.
⁸⁸https://gluonhq.com/products/scene-builder/
Chapter 7: About JavaFX 167
If you want to experiment with FXML to generate JavaFX user interfaces, Scene Builder is worth a
try!
Just a thought - Beware of the PAF
I first learned about the “WAF” at work during a lunch discussion between engineers, on self-
made domotics projects. The major reason such a project fails or succeeds is the “Wife Acceptance
Factor”. According to some, the same WAF is the most critical point in every decision when buying
a new television, radio or any electronic device with a complex remote control.
But as I strongly believe technology is not a man-only thing, the “W” in “WAF” gives me even more
grey hair than I already have… Technology is not male – or at least it should not be at all. So that’s
why I officially rename “WAF” to “PAF” now, “Partner Acceptance Factor”!
I went through this renaming-process before. At my job, we were selling devices with the name
“MMI”, “Man-Machine Interface”. It’s a touch screen device used by the train driver to select the
journey, which announcements need to be played back, answer an emergency call, etc. But not
all train drivers are male of course. So by introducing the new name “HMI”, “Human-Machine
Interface” in one project, I was able to slowly break into the company’s history of product naming
and turn this unfriendly name into a new one.
It’s only a small step of course, but as we also do with CoderDojo (a computer club for kids), we
need to convince girls technology is fun! Diversifying the group of people working in technology
is important. Good products can only be made if the people involved are a good mixture of age,
gender, origin…
As STEAM (Science, Technology, Engineering, Arts and Mathematics) receives more and more
attention in education, we see a slow change in the number of girls choosing for a scientific
trajectory. This book is my own little attempt to make sure enough fun and simple getting-started
projects are available to inspire “kids” of any age.
Oh, and as a side note, if anyone asks why you would build something yourself if you can buy it
off-the-shelf, the correct answer is “Because I can!”. Even if you fail during the process, you will
have learned new things!
While working on this book, I also encountered the “CAF”, the “Community Acceptance Factor”.
Using Java on the Pi seems to be a polarizing subject according to Mark Heckler (Spring Developer
& Advocate at Pivotal Software). You either totally love it or hate it, no middle ground. To some, a
Pi is made for Python. Of course, I don’t agree ;-) Python is great and you can get started with it
very quickly, but I don’t like the user interfaces you can make with it (and I tried!). JavaFX provides
way better code for this. On the other hand, I have to repeat myself… Why do I prefer Java on the
Pi? “BECAUSE WE CAN!”
https://www.youtube.com/watch?v=yMtzJCo6nAk
Chapter 8: Bits and bytes
A lot of interactions with the GPIOs require some understanding of bits and bytes. Let’s dive into a
quick summary.
Very short:
• All logic inside the brain of a computer is a bit which can be 0 or 1 (off or on).
• When you combine 8 bits, you get a byte.
Bits make it very easy to handle data, true or false, nothing else.
But in the next years, quantum computers should become available, and they use qubits
which can be 0 AND 1 at the same time, what is called superposition⁸⁹. The first “Proof of
Principle” quantum computers are already available and they use 20 to 50 qubits. This looks
a very small number compared to the Gigabyte memory and storage we now have on PCs,
even the Pi.
But quantum computers use their qubits at the same time, so if there are 20 qubits,
2^20 number of parallel computations can be achieved and can solve problems which are
impossible to solve with current supercomputers. Breaking encryption keys, simulating the
effect of new medicines, correctly predicting the weather… are just a few examples.
The goal is to reach a quantum computer with 300 qubits. And the value 2^300 is bigger
than the number of atoms in the whole universe⁹⁰! If a quantum computer with 50 qubits
is capable of breaking all currently known encryptions in seconds, what will one with 300
qubits be able to do?!
Programming a quantum computer will be very challenging as even the most intelligent
physicist and mathematicians find it hard to understand the principles of all quantum stuff⁹¹.
So, let’s just stick to our 0 OR 1 for now ;-)
⁸⁹https://en.wikipedia.org/wiki/Quantum_superposition
⁹⁰https://www.quora.com/What-is-2-raised-to-the-power-of-300
⁹¹https://hubpages.com/education/QuantumVagary
Chapter 8: Bits and bytes 170
Bits 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 + Totaal HEX
128 64 32 16 8 4 2 1
00001111 0 0 0 0 1 1 1 1 8+4+2+1 15 x0F
00011111 0 0 0 1 1 1 1 1 16+…+1 31 x1F
00100000 0 0 1 0 0 0 0 0 32 32 x20
11111111 1 1 1 1 1 1 1 1 128+…+1 255 xFF
To fully understand how this is converted for all possible bit combinations, you can use the
sample application from the sources with a JavaFX application:
Chapter_08_BitsAndBytes > javafx-bits-calculator
1 class PrintLimits {
2 public static void main(String[] args) {
3 System.out.println("Byte");
4 System.out.println(" Min: " + Byte.MIN_VALUE);
5 System.out.println(" Max: " + Byte.MAX_VALUE);
6
7 System.out.println("Short");
8 System.out.println(" Min: " + Short.MIN_VALUE);
9 System.out.println(" Max: " + Short.MAX_VALUE);
10
11 System.out.println("Integer");
12 System.out.println(" Min: " + Integer.MIN_VALUE);
13 System.out.println(" Max: " + Integer.MAX_VALUE);
14
15 System.out.println("Long");
16 System.out.println(" Min: " + Long.MIN_VALUE);
17 System.out.println(" Max: " + Long.MAX_VALUE);
18 }
19 }
1 Byte
2 Min: -128
3 Max: 127
4 Short
5 Min: -32768
6 Max: 32767
7 Integer
8 Min: -2147483648
9 Max: 2147483647
10 Long
11 Min: -9223372036854775808
12 Max: 9223372036854775807
Hmm, this is unexpected! Does a byte have the range of -128 to 127, instead of 0 to 255?!
On some forums, there was some confusion and someone thought he was doing things
wrong as he expected a different value during testing. To understand this, we need to know
the difference between signed and unsigned values!
The same goes for a short which consist of two bytes (= 16 bits), for example, “1000 0000 0000 1111”:
Chapter 8: Bits and bytes 174
Hex value 0x800f is both 32873 and -15 depending on how you convert it
Conclusion
You need to be sure how you handle numeric values when you read them out to not confuse between
the signed and unsigned value!
Luckily we have the Byte.toUnsignedInt(b) and Integer.toUnsignedString(i) methods to make sure
we are reading out the correct value when logging. Here a quick demo with some byte and integer
values:
1 class HexIntegerToString {
2 public static void main(String[] args) {
3 convertByte((byte) 8);
4 convertByte((byte) 124);
5 convertByte((byte) 170);
6
7 convertInteger(0x7FFFFFFF);
8 convertInteger(0x80000001);
9 }
10
11 private static void convertByte(byte value) {
12 System.out.println("Byte Unsigned: "
13 + Byte.toUnsignedInt(value)
14 + "\tSigned: " + value);
15 System.out.println(" Hex value: 0x"
16 + Integer.toHexString(value & 0xFF));
17 System.out.println(" Binair: "
18 + padLeftZero(Integer.toBinaryString(value & 0xFF), 8));
19 }
Chapter 8: Bits and bytes 175
20
21 private static void convertInteger(int value) {
22 System.out.println("Integer Unsigned: "
23 + Integer.toUnsignedString(value)
24 + "\tSigned: " + Integer.toString(value));
25 System.out.println(" Hex value: 0x"
26 + Integer.toHexString(value));
27 System.out.println(" Binair: "
28 + padLeftZero(Integer.toBinaryString(value), 32));
29 }
30
31 private static String padLeftZero(String txt, int length) {
32 StringBuilder rt = new StringBuilder();
33 for (int i = 0; i < (length - txt.length()); i++) {
34 rt.append("0");
35 }
36 return rt.append(txt).toString();
37 }
38 }
When running this code, we get this output with the expected and readable values:
1 $ java HexIntegerToString.java
2 Byte Unsigned: 8 Signed: 8
3 Hex value: 0x8
4 Binair: 00001000
5 Byte Unsigned: 124 Signed: 124
6 Hex value: 0x7c
7 Binair: 01111100
8 Byte Unsigned: 170 Signed: -86
9 Hex value: 0xaa
10 Binair: 10101010
11 Integer Unsigned: 2147483647 Signed: 2147483647
12 Hex value: 0x7fffffff
13 Binair: 01111111111111111111111111111111
14 Integer Unsigned: 2147483649 Signed: -2147483647
15 Hex value: 0x80000001
16 Binair: 10000000000000000000000000000001
Chapter 8: Bits and bytes 176
Web colors
The most known use of hex bytes is the definition of colors in HTML. Colors are defined with three
bytes for red, green and blue. Some examples:
Each segment is an LED with its own pin so it can be controlled separately. To easily understand
which segment will be used, they are identified as A till H.
⁹²https://www.w3schools.com/colors/colors_rgb.asp
Chapter 8: Bits and bytes 177
LED number display with the segments B and C on, showing the number 1
For the numbers 0 till 9 we can define the hex value to turn on the desired segments. E.g. for the 0
we need segments A till F, not G and H. So the 6 lowest bits 00111111 which is equal to 0x3f.
This is the full table to control the 8 segments with one hex value to indicate which of the 8 LED(s)
we want to be on.
LED display h g f e d c b a Hex value Number value
0 0 0 1 1 1 1 1 1 0x3f 63
1 0 0 0 0 0 1 1 0 0x06 6
2 0 1 0 1 1 0 1 1 0x5b 91
3 0 1 0 0 1 1 1 1 0x4f 79
4 0 1 1 0 0 1 1 0 0x66 102
5 0 1 1 0 1 1 0 1 0x6d 109
6 0 1 1 1 1 1 0 1 0x7d 125
7 0 0 0 0 0 1 1 1 0x07 7
8 0 1 1 1 1 1 1 1 0x7f 127
9 0 1 1 0 1 1 1 1 0x6f 111
Just like RGB-LEDs (see “Chapter 2: Tools” > “Hardware” > “RGB-LED”) these displays exist in two
“flavours” with common cathode (-) or anode (+). For this example, we need a common cathode type
as each LED will get its power from a separate pin of the IC, so an 5101AS (datasheet)⁹³ was used.
⁹³https://www.datasheets360.com/pdf/-5896711825166489141
Chapter 8: Bits and bytes 178
The Pi has enough GPIO connections to control these 8 LED segments. And you can control them
the same way as we have done before in the JavaFX chapter with the Gpio.java class. For instance,
turning one segment on connected to pin with wiringpi number 5 would be done like this:
But this means we need 8 pins for 8 segments and if we would be building a more complex project,
we could quickly run out of GPIOs… Let’s take a better approach and use a bit shift register. This is
a digital circuit that can be used to extend the number of GPIOs of a Pi (or Arduino).
In our case, we will work with the SN74HC595, a Serial-In-Parallel-Out shift register. Instead of 8,
we will only need three of the Pi GPIOs to control 8 LED segments.
First, we take a look a the technical sheet⁹⁴ to be sure what we can do with it and how to connect it.
This is the pin-listing with a reference to the variable we will use in the Python script “shift.py”:
Wiring
Before connecting the IC, you can first try all connections to the LED segment display with a fixed
3.3V input instead of a GPIO.
⁹⁴https://www.ti.com/lit/ds/symlink/sn74hc595.pdf
Chapter 8: Bits and bytes 179
Always double-check which resistors you need to use and the expected input voltage. Not
all LEDs are forgiving when you are applying a too high voltage.
At least one component died during the writing of this book…
After we have checked the LED segments are working with the fixed power supply, we can start
with the full connections including the IC.
A picture, of course, is not very clear to get the correct wiring, so below you find a Fritzing
breadboard and scheme which is also available in the sources:
Chapter_08_BitsAndBytes > schemes > 74NC595-led-number.fzz
Chapter 8: Bits and bytes 180
This is the same wiring but another view to make things even more clear:
Chapter 8: Bits and bytes 181
In the previous chapter, we used Gpio.java to execute terminal commands from Java to toggle and
read GPIOs. In the next chapter, we will be working with Pi4J so we can control the GPIOs directly
from within Java. But in this chapter, we take yet another approach and use a Python script to
execute multiple GPIO interactions in one flow.
This script will be included in the Java application so it can be called from within the application
and needs to execute these steps:
Let us first create a Python file “shift.py” (e.g. in “/home/pi”) on the Pi, so we can start it in the
terminal with a number value as start-up argument, e.g. number 109 (see the table before) to show
a “5” on the segment display:
The Python script sets the bits of this value 109 to the 8 memory positions of the SN74HC595. This
is the full script:
1 # coding=utf-8
2
3 import RPi.GPIO as GPIO
4 import time
5 import sys
6
7 # Define BCM pin numbers
8 PIN_DATA = 4
9 PIN_SRCLK = 5
10 PIN_RCLK_LATCH = 6
11 WAIT_TIME = 0.01
12
13 # Ignore GPIO warnings as we are re-using pins
14 GPIO.setwarnings(False)
15
16 # Initialize pins
17 GPIO.setmode(GPIO.BCM)
Chapter 8: Bits and bytes 182
18 GPIO.setup(PIN_DATA, GPIO.OUT)
19 GPIO.setup(PIN_SRCLK, GPIO.OUT)
20 GPIO.setup(PIN_RCLK_LATCH, GPIO.OUT)
21
22 # Get value from startup argument
23 inputValue = 0xff
24
25 print "Number of arguments: " + str(len(sys.argv))
26
27 if len(sys.argv) > 1:
28 if sys.argv[1].startswith('0x'):
29 # This is used to parse a hex value in format "0x00" into an integer
30 inputValue = int(sys.argv[1], 16)
31 else:
32 # Parsing other values to integer
33 inputValue = int(sys.argv[1])
34
35 print "Sending value: " + str(inputValue)
36
37 # Set the RELEASE pin low so the values are stored in memory
38 GPIO.output(PIN_RCLK_LATCH, 0)
39 time.sleep(WAIT_TIME)
40
41 for y in range(8):
42 # Set the DATA pin to the bit y of the given value
43 bit = inputValue >> (7 - y) & 1
44 print "Sending bit value " + str(bit) + " to slot " + str(y)
45
46 # Prepare for the next value by setting the CLOCK pin LOW
47 GPIO.output(PIN_SRCLK, 0)
48 time.sleep(WAIT_TIME)
49
50 # Set the data (high or low state) for the pin y
51 GPIO.output(PIN_DATA, bit)
52 time.sleep(WAIT_TIME)
53
54 # Set the CLOCK pin HIGH to store the DATA value into memory
55 GPIO.output(PIN_SRCLK, 1)
56 time.sleep(WAIT_TIME)
57
58 # Loop is finished, so all 8 values are sent
59 # Set the RELEASE pin high so the values from memory are sent to the outputs
60 GPIO.output(PIN_RCLK_LATCH, 1)
Chapter 8: Bits and bytes 183
61 time.sleep(WAIT_TIME)
62
63 print "Done"
With the comments in the code this should be pretty self-explaining, but let us take out one special
line from the for-loop to get bit per bit from the inputValue:
When we run this script in the terminal we get the following output matching this table:
But we can also call the same script with a HEX value when we start it with “0x” as this is converted
correctly inside the script:
Chapter 8: Bits and bytes 184
Now let’s make a user interface in JavaFX to easily test these bits to/from hex conversion.
LED segment test application showing the selected segments as bits, hex value and number value
We can start again with a copy from the minimal JavaFX application from Chapter 7 and rename
the project to “lednumberdisplaycontroller”. Copy the script “shift.py” we created before, into the
resources directory of our Java project. This way, it will be packaged into the .jar-file with our
application which we will run on the Pi.
Chapter 8: Bits and bytes 185
Java project structure with the shift.py added in the resources directory
We need to change the pom-artifactId and add a dependency to the library “javafx-led-number-
display” which has been published into the Maven repository, to easily visualize an LED segment
display in JavaFX.
1 <groupId>be.webtechie</groupId>
2 <artifactId>led-number-display-controller</artifactId>
3
4 <dependencies>
5 ...
6 <dependency>
7 <groupId>be.webtechie</groupId>
8 <artifactId>javafx-led-number-display</artifactId>
9 <version>0.0.3</version>
10 </dependency>
11 </dependencies>
In this same pom.xml file we also need to add a plugin to be able to build a jar-file which includes the
extra dependency and we don’t need to install it on the device where we want to run this application.
If you use a different package name for the App-class you need to update the mainClass-value.
⁹⁵https://github.com/FDelporte/JavaFXLedNumberDisplay
Chapter 8: Bits and bytes 186
1 <plugins>
2 ...
3 <plugin>
4 <artifactId>maven-assembly-plugin</artifactId>
5 <version>2.2.1</version>
6 <configuration>
7 <descriptorRefs>
8 <descriptorRef>jar-with-dependencies</descriptorRef>
9 </descriptorRefs>
10 <archive>
11 <manifest>
12 <addClasspath>true</addClasspath>
13 <mainClass>be.webtechie.lednumberdisplaycontroller.App</mainClass>
14 </manifest>
15 </archive>
16 </configuration>
17 <executions>
18 <execution>
19 <id>make-assembly</id>
20 <phase>package</phase>
21 <goals>
22 <goal>single</goal>
23 </goals>
24 </execution>
25 </executions>
26 </plugin>
27 </plugins>
44 }
45 }
Take a look at the full code of this class SegmentSelection.java and feel free to “adjust-and-mess-up”
to see how this works. Only the most important parts are described here.
1 /**
2 * Generate a black holder with an LED number display component from
3 * the Maven dependency be.webtechie.javafx-led-number-display.
4 *
5 * @return {@link HBox} with the led number display
6 */
7 private HBox generateHighlightSelection() {
8 HBox holder = new HBox();
9 holder.setStyle("-fx-background-color: black;");
10 holder.setPadding(new Insets(25));
11 holder.setAlignment(Pos.CENTER);
12
13 this.ledNumberDisplay = new LedNumber(DisplaySkin.CLASSIC,
14 Color.BLACK, Color.DARKGRAY, Color.RED);
15 this.ledNumberDisplay.setMaxHeight(105);
16 holder.getChildren().add(this.ledNumberDisplay);
17
18 return holder;
19 }
Chapter 8: Bits and bytes 189
1 /**
2 * Generate the holder with a dropdown with highlight presets
3 * and 8 checkboxes to be able each segment separately.
4 *
5 * return {@link HBox} with combobox and checkboxes
6 */
7 private VBox generateBitSelection() {
8 VBox selectionsHolder = new VBox();
9 selectionsHolder.setSpacing(10);
10 selectionsHolder.setAlignment(Pos.CENTER);
11
12 this.selectHighLightType = new ComboBox<>();
13 this.selectHighLightType.getItems().setAll(HighlightType.values());
14 this.selectHighLightType.setOnAction(this::updateHighlights);
15 selectionsHolder.getChildren().add(this.selectHighLightType);
16
17 this.cbA = new CheckBox("A (0x01)");
18 this.cbA.setOnAction(this::updateFromBits);
19 this.cbB = new CheckBox("B (0x02)");
20 this.cbB.setOnAction(this::updateFromBits);
21 ...
22
23 selectionsHolder.getChildren().addAll(
24 this.cbH, this.cbG, this.cbF, this.cbE,
25 this.cbD, this.cbC, this.cbB, this.cbA
26 );
27
28 return selectionsHolder;
Chapter 8: Bits and bytes 190
29 }
In the Maven library an enum is available with a list of possible HighlightTypes, which we use to
fill a combobox. These HighlightTypes can be checked in the source of the Maven library (see link
before) and look like this:
1 /**
2 * Enum with definition of the segments to be highlighted.
3 *
4 * Placing of the LEDs:
5 * AAAA
6 * F B
7 * GGGG
8 * E C
9 * DDDD
10 */
11 public enum HighlightType {
12 CLEAR(false, false, false, false, false, false, false),
13
14 ZERO(true, true, true, true, true, true, false),
15 ONE(false, true, true, false, false, false, false),
16 TWO(true, true, false, true, true, false, true),
17 ...
18 }
When the user changes the selection in the combobox all the checkboxes are adjusted to represent
the selected HighlightType. When this is done “setValue()” is called to send this new value to the
Python script.
Chapter 8: Bits and bytes 191
1 /**
2 * Change the states of all the {@link ComboBox} to match
3 * the selected {@link HighlightType}
4 */
5 private void updateHighlights(ActionEvent actionEvent) {
6 HighlightType highlightType = this.selectHighLightType.getValue();
7
8 if (highlightType == null) {
9 return;
10 }
11
12 this.ledNumberDisplay.highlight(highlightType, this.cbH.isSelected());
13
14 this.cbA.setSelected(highlightType.isA());
15 this.cbB.setSelected(highlightType.isB());
16 this.cbC.setSelected(highlightType.isC());
17 this.cbD.setSelected(highlightType.isD());
18 this.cbE.setSelected(highlightType.isE());
19 this.cbF.setSelected(highlightType.isF());
20 this.cbG.setSelected(highlightType.isG());
21
22 this.setValue();
23 }
Whenever a new HighlightType is selected in the dropdown or a CheckBox is (de)selected, the value
is recalculated, and the Python script is executed. The calculated value is also shown in a label inside
the UI as bits, hex and integer value.
1 /**
2 * Calculate the value base on the selected {@link ComboBox},
3 * display in the label of the UI and send to the hardware
4 * by calling the Python script.
5 */
6 private void setValue() {
7 int value = (this.cbA.isSelected() ? 0x01 : 0x00)
8 + (this.cbB.isSelected() ? 0x02 : 0x00)
9 + (this.cbC.isSelected() ? 0x04 : 0x00)
10 + (this.cbD.isSelected() ? 0x08 : 0x00)
Chapter 8: Bits and bytes 192
When this is finished, you’ll find two jar-files in the target directory of your project:
Chapter 8: Bits and bytes 193
And there we have it! A nice JavaFX UI, integrated use of a Python script and a fully functional
hardware setup with an IC and LED segment display. Nice work! :-)
What’s next?
• Use 6 LEDs instead of the LED segment display to make an electronic dice.
• Use more of these ICs to connect even more LEDs or other output devices. On the Arduino
website you can find an example of this⁹⁶ to use as a base to achieve the same with Java and
Pi.
• Control a set of relays to turn devices on or off with higher voltage needs than the Pi can
deliver.
⁹⁶https://www.arduino.cc/en/Tutorial/ShiftOut
Chapter 9: PI4J
Pi4J is the best library to link Java on the Raspberry Pi with the GPIOs. In our earlier experiments
with the JavaFX dashboard (see “Chapter 7”), we created our own Gpio.java but this was only able
to set a pin high or low and read a pin state via “terminal commands”. The Pi4J library offers a lot
more methods directly connected to the hardware for optimal performance.
The open-source project was started by Robert Savage and Daniel Sendula and the code is available
on GitHub⁹⁷.
In 2019 a full rework of this library started to bring it more in line with modern Java and to be able to
handle new types of Raspberry Pi’s more easily. Unfortunately, this new version is not available yet,
so the following examples still use version 1.2 but should be easily adaptable later. All the examples
in this chapter were developed on a Raspberry 3 B+.
As the Raspberry Pi 4 uses a new chip, some of the interior wirings are different compared to the
previous Pi’s. Make sure to update WiringPi⁹⁸ if you want to experiment with Pi4J on a Pi 4, as this
is the interface between Pi4J and the hardware, as described in Chapter 5 > WiringPi number.
All methods of Pi4J are documented with JavaDoc and the generated HTML documentation can be
found on www.pi4j.com/1.2/apidocs/index.html⁹⁹.
⁹⁷https://github.com/Pi4J/pi4j/
⁹⁸http://wiringpi.com/download-and-install/
⁹⁹https://www.pi4j.com/1.2/apidocs/
Chapter 9: PI4J 196
Installation
Adding the Pi4J framework to your Pi can be done with one single command which will download
and launch an installation script that performs the following steps:
By using this method, you can also update to newer versions later with the following commands:
Sources
All of the sources for these example applications are available in:
Chapter_09_Pi4J
For example the first example with the RGB-LED:
Chapter_09_Pi4J > java-pi4j-digital-ouput-led
The electronic schemes designed with Fritzing can be found in:
Chapter_09_Pi4J > schemes
Some of the examples also use an Arduino and the code for these projects can also be found
in this same directory, e.g.:
Chapter_09_Pi4J > arduino-serial
Maven dependencies
To add Pi4J to a Java Maven project we need to add at least this dependency in the pom file:
1 <dependency>
2 <groupId>com.pi4j</groupId>
3 <artifactId>pi4j-core</artifactId>
4 <version>1.2</version>
5 </dependency>
Some of the examples need additional dependencies. Check the pom.xml-file of each example in
the sources to check the required dependencies. For example, when an LCD-display needs to be
controlled, this additional one must be added:
1 <dependency>
2 <groupId>com.pi4j</groupId>
3 <artifactId>pi4j-device</artifactId>
4 <version>1.2</version>
5 </dependency>
Chapter 9: PI4J 198
The full list of Pi4J dependencies can be found in the Maven Repository of com.pi4j¹⁰⁰.
Also used in some of the examples: unit tests. We didn’t use them a lot in this book yet, but they
should be part of any good development! So where applicable, you can find some unit tests in this
project not only as example code but also to validate the code of the examples itself of course. For
the unit tests, this dependency is needed:
1 <dependency>
2 <groupId>junit</groupId>
3 <artifactId>junit</artifactId>
4 <version>4.12</version>
5 <scope>test</scope>
6 </dependency>
As you can see, an additional value is added “<scope>test</scope>” because this dependency should
not be added to the final package, but is only needed during testing.
Some of the examples use jackson-databind to convert a JSON string to a Java object as further
explained. This is the required dependency for these applications:
1 <dependency>
2 <groupId>com.fasterxml.jackson.core</groupId>
3 <artifactId>jackson-databind</artifactId>
4 <version>2.10.1</version>
5 </dependency>
¹⁰⁰https://mvnrepository.com/artifact/com.pi4j/
Chapter 9: PI4J 199
JSON = JavaScript Object Notation¹⁰¹ is a commonly used way to structure data. For
example:
1 {
2 "type": "measurement",
3 "data": {
4 "sensor1": 123,
5 "sensor2": 456
6 }
7 }
This format allows organizing data in a human-readable way which is also easy to be parsed
by a programming language.
XML = Extensible Markup Language¹⁰² is another way to achieve this. The same data could
be structured like this, but the formatting is up to the developer:
1 <message>
2 <type>measurement</type>
3 <dataset>
4 <data source="sensor1">123</data>
5 <data source="sensor2">456</data>
6 <dataset>
7 </message>
Which format is best, is open for discussion, but with the current frameworks, there is no
big performance issue between the parsing of both. Just try to stick to one method.
Where the application needs more permissions, it needs to be started as a jar. You’ll need to create
the jar and start it from the terminal. For example:
For some of the applications you’ll also need to start with sudo:
Make sure you have a common cathode LED by directly connecting one of the color pins to the 3.3V
output of the Pi and use a resistor (330Ω will work for most). Then connect each of the RGB pins to
a GPIO and the common pin to a ground pin.
Depending on the type of RGB-LED each color needs another resistor value because each one has
a different operating voltage. So this quick example with one resistor on the cathode side causes in
my case to have a very dominant, bright red. When all three GPIOs are high, the mixed color is red
instead of white.
Chapter 9: PI4J 205
To achieve a correct color mix, you will need to check the datasheet of your RGB-LED to calculate
the correct resistor for each pin. But when setting up this experiment, as there was no article number
or datasheet available, the trial-and-error approach has been used… With a 220Ω resistor between
the GPIO and the red pin and a 100Ω one on the green and blue pin, the mixed color is nearly white.
The adjusted wiring looks like this:
If you don’t know how to connect this kind of button, use the fixed 3.3V and an LED to detect how
to push the button into the breadboard. You have a 50% chance to be first-time-right. In my case
second-time-right…
To simplify the code we add a separate class that implements GpioPinListenerDigital. In this class,
we can count the number of presses and log the time difference with the previous press.
1 /**
2 * Listener which will be called each time the button is pressed.
3 */
4 public class InputChangeEventListener implements GpioPinListenerDigital {
5 private int numberOfPresses = 0;
6 private long lastPress = System.currentTimeMillis();
7
8 /**
9 * Event handler
10 */
11 @Override
12 public void handleGpioPinDigitalStateChangeEvent(
13 GpioPinDigitalStateChangeEvent event) {
14
15 if (event.getState() == PinState.HIGH) {
Chapter 9: PI4J 207
16 this.numberOfPresses++;
17
18 long diff = System.currentTimeMillis() - this.lastPress;
19
20 System.out.println("Button pressed for "
21 + this.numberOfPresses + "th time, diff: "
22 + diff + "millis");
23
24 this.lastPress = System.currentTimeMillis();
25 }
26 }
27
28 /**
29 * @return the number of times the button has been pressed
30 */
31 public int getNumberOfPresses() {
32 return this.numberOfPresses;
33 }
34 }
• Define the input GPIO number, in this example WiringPi n° 5 = BCM 24.
• Initialize GpioPinDigitalInput and add the listener class.
• Wait until the button is pressed 10 times.
15
16 // Initialize the input pin with pull down resistor
17 GpioPinDigitalInput button = gpio.provisionDigitalInputPin(
18 PIN_BUTTON, "Button", PinPullResistance.PULL_DOWN);
19
20 // Attach an event listener
21 listener = new InputChangeEventListener();
22 button.addListener(listener);
23
24 // Loop until the button has been pressed 10 times
25 while (listener.getNumberOfPresses() < 10) {
26 Thread.sleep(10);
27 }
28
29 // Shut down the GPIO controller
30 gpio.shutdown();
31
32 System.out.println("Done");
33 } catch (Exception ex) {
34 System.err.println("Error: " + ex.getMessage());
35 }
36 }
37 }
We test this application with “mvn clean package” and “java -jar”. When trying to push the button
every second, the result looks like this:
Let’s try what a pull-down resistor adds as functionality as described in “Chapter 5: Raspberry Pi
pinning > Pin types > Digital GPIO”.
Go back to the main class and change the initialization of GpioPinDigitalInput to:
Now run the application the same way without touching the button and you’ll get this kind of
output:
The GPIO toggles so fast the output gets completely messed up. As you can see the log output gives
unreliable results.
When using a pull-up resistor, no button presses are detected at all.
the system used by a bat to fly in the dark without hitting walls. The reflection of ultrasound is used
to calculate the distance to an object on which the sound reflects.
To measure the distance, these steps must be taken:
As this sensor module works on 5V, we need to limit the current going back to the Pi to not damage
the GPIO which expects max 3.3V. This is done with the resistors which also connect the echo pin
to the ground to have a clear difference between high and low (pull-down).
Code blocks
As we will need to do some calculations on the measured results, a separate “Calculation.java” class
is used to provide these methods.
1 /**
2 * Helper class for duration and distance calculation.
3 */
4 public class Calculation {
5 /**
6 * Get the distance (in cm) for a given duration.
7 * The calculation is based on the speed of sound which is 34300 cm/s.
8 *
9 * @param seconds Number of seconds
10 * @param half Flag to define if the calculated distance must be divided
11 */
12 public static int getDistance(float seconds, boolean half) {
13 float distance = seconds * 34300;
14 return Math.round(half ? distance / 2 : distance);
15 }
16
17 /**
18 * Get the number of seconds between two nanosecond timestamps.
19 * 1 second = 1000000000 nanoseconds
20 *
21 * @param start Start timestamp in nanoseconds
22 * @param end End timestamp in nanoseconds
23 */
24 public static float getSecondsDifference(long start, long end) {
25 return (end - start) / 1000000000F;
26 }
27 }
Unit test
To validate these functions, a unit test “CalculationTest.java” is also added to the example code
which checks the results of these methods. “assertEquals” checks if the test result is OK.
Chapter 9: PI4J 212
When you run this class, your IDE will show the result for each test separately:
Chapter 9: PI4J 213
Application code
Now let’s write the application code. In the “main”-method the pins are initialized. We keep looping
to do continuous distance measurements every 2 seconds. The call to “measureDistance()” allows us
to keep this method very clean and isolate the measurement code.
25 Thread.sleep(2000);
26 }
27 } catch (Exception ex) {
28 System.err.println("Error: " + ex.getMessage());
29 }
30 }
31 }
Of course, we still need to add the measureDistance-method. In the example code, it is part of the
same App-class but you could also put it in a separate one. Within this method, each step is taken
as described at the beginning of this example to put the trigger pin high and measure the duration
between the state changes of the echo pin. Using the methods created before in the Calculation-class
we can now log the distance between the distance sensor and the nearest object.
When we build and run the application, we get a log-line every 2 seconds with the measurement
between the distance sensor and … euh … for this example my hand going back and forth :-)
Oh, and my test setup is about 3m from the wall as the last measurement shows.
Chapter 9: PI4J 216
PWM example
As described in “Chapter 5: Raspberry Pi pinning”, PWM (Pulse-Width Modulation) can be used to
create a “semi-analog output”.
In this example, we are going to control the brightness of LED by using a PWM signal.
44 }
The LEDs inside the matrix are connected as shown in the previous image. By putting power on a
row, and connecting a column to the ground, a specific LED can be put on. When this is done faster
than the eye can see, multiple LEDs look to be continuously powered while they are actually toggled
very fast.
Wiring
SPI requires four connections, but as we don’t read data back, we only connect three of them plus
power and ground.
Chapter 9: PI4J 220
Test setup
¹⁰³https://www.sparkfun.com/datasheets/Components/General/COM-09622-MAX7219-MAX7221.pdf
Chapter 9: PI4J 221
Again, to make everything more clear, the code is split into small blocks.
Definitions
Let’s first start with a list of commands, not including the rows as we will just use the row number
later so don’t need to define a command for them.
1 /**
2 * Reserved byte values to send a command.
3 */
4 public enum SpiCommand {
5 DECODE_MODE((byte) 0x09),
6 BRIGHTNESS((byte) 0x0A),
7 SCAN_LIMIT((byte) 0x0B),
8 SHUTDOWN_MODE((byte) 0x0C),
9 TEST((byte) 0x0F);
10
11 private final byte value;
12
13 SpiCommand(byte value) {
14 this.value = value;
15 }
16
17 public byte getValue() {
18 return value;
19 }
20 }
Two types of enums are also created: images and characters, with an image always being 8 by 8 in
size, but the characters can have a different width, depending on the number of columns needed to
draw the character.
Chapter 9: PI4J 222
Let’s start with the images. Only two are included here, but there are more in the sources in the
GitHub-repository and of course, you can add as many as you want! We need byte values, but it’s
more clear to create these as strings with 0s and 1s for each LED. These string values are converted
to a byte for each row, so we need 8 of them for each image.
A little trick, when you do a “Find” on “1” in your IDE, the created image becomes a lot more clear!
Chapter 9: PI4J 223
Similarly, the characters are created, with additional info about ASCII-code and the number of
columns used for the character. Check for instance the difference between “B” (6 columns) and “T”
(5 columns).
ASCII is the standard that defines a value for each character. The first 32 are unprintable control
codes like backspace, tab, line break etc. Codes 32 till 127 are used for letters, digits, punctuation
marks, miscellaneous symbols… Starting from 128 is extended ASCII with special characters like é,
®, ¾.
A quick overview:
Building a character on a matrix can be challenging. So again only a few examples and more
homework for you :-)
Chapter 9: PI4J 224
44 return rows;
45 }
46
47 public static AsciiCharacter getByAscii(int ascii) {
48 for (AsciiCharacter asciiCharacter : AsciiCharacter.values()) {
49 if (asciiCharacter.getAscii() == ascii) {
50 return asciiCharacter;
51 }
52 }
53 return null;
54 }
55
56 public static AsciiCharacter getByChar(char character) {
57 return getByAscii(character);
58 }
59 }
Width of B versus T
The ASCII code could be used to find the matching enum for a given character if you want to extend
the application with a method to display a certain text on the matrix display. To get that code we
can use the “charAt”-method:
Helpers
Sending visual output to the matrix via the SPI through the chip is split into three classes, so you
can easily play with it, add other methods, etc.
First, there is a general “Demo” one. Check the JavaDoc on each method and the logging as these
explain what each one is doing.
87 }
That was all the hard work! Initializing the SPI and sending content is now a small remaining step we
can do in the main-method where we call the different methods from the DemoMode-, ImageMode-
and AsciiCharacterMode-classes.
36 ImageMode.showAllImages(spi, 2000);
37 AsciiCharacterMode.showAllAsciiCharacters(spi, 750);
38 AsciiCharacterMode.scrollAllAsciiCharacters(spi, 50);
39 } catch (Exception ex) {
40 System.err.println("Error in main function: " + ex.getMessage());
41 }
42 }
43 }
SPI conclusion
Homework left for you in this example! Not the complete ASCII-set is included and you can now only
let one character scroll at a time, not a whole sentence… Hop hop, get to work now and experiment!
Chapter 9: PI4J 234
Wiring
Connect the sensor to the 5V on one side, and the other side to the A0 analog pin of the Arduino
board. With a 10kΩ resistor connected between the A0-connection and the ground, we add a pull-
down system to have a good measurement.
Chapter 9: PI4J 235
We will first connect the Arduino to the PC to program and test it. Later the same USB-cable is used
to connect the Arduino board directly to the Pi.
Test setup
Arduino code
For this example application, we use a simple Arduino script to:
1 int loopCounter = 0;
2 int maxLoopCounter = 200;
3
4 int analogPinLightSensor = 0;
5
6 void setup() {
7 Serial.begin(38400);
8 }
9
10 void loop() {
11 if (Serial.available() > 0) {
12 String received = Serial.readStringUntil('\n');
13
14 Serial.print("{\"type\":\"echo\",\"value\":\"");
15 Serial.print(received);
16 Serial.println("\"}");
17 }
18
19 loopCounter++;
20
21 if (loopCounter > maxLoopCounter) {
22 Serial.print("{\"type\":\"light\",\"value\":");
23 Serial.print(analogRead(analogPinLightSensor));
24 Serial.println("}");
25
26 loopCounter = 0;
27 }
28
29 delay(10);
30 }
Please note the difference between “Serial.print” and “Serial.println”. The first one is used to
construct parts of a sentence, while “println” ends the line by adding a line-break at the end. This is
the identifier for the receiver to handle all the data it has received until that point.
When you upload this code to your Arduino board and open the “Serial Monitor”, you will
immediately see the sensor value output. When you send a message, the echo also appears in the
output window.
Chapter 9: PI4J 237
1 dmesg
This command will give you the latest logging of the Linux kernel which also contains the messages
produced by the device drivers. We are looking for an address starting with ‘tty’:
Raspberry Pi code
Again for readability, maintainability, and testability, the code is split into different small classes.
Start from the javafx-minimal example and extend the pom-file with the pi4j-core and jackson-
databind dependencies.
Arduino message
As we saw in the Arduino code, every few seconds a new light measurement value is sent through
the serial connection. The JSON format of this data is:
Chapter 9: PI4J 238
1 {"type":"light","value":394}
To be able to handle this easily in the application we need to convert it to a Java object and jackson-
databind takes care of this for us with the @JsonProperty-annotations. Some additional get-methods
are added as we could be using this type/value-pair for any type of data and values. For instance,
the echo-type will contain a String, the light-type will contain an analog value between 0 and 1024.
Serial sender
This implements runnable as we will later start the class in a separate thread, to send a timestamp
to the Arduino board to demonstrate the echo function.
23
24 // Wait predefined time for next loop
25 Thread.sleep(INTERVAL_SEND_SECONDS * 1000);
26 } catch (Exception ex) {
27 System.err.println("Error: " + ex.getMessage());
28 keepRunning = false;
29 }
30 }
31 }
32 }
Serial listener
Listener which will print out the data received on the serial connection
Measurement chart
Here we handle the generation of the user interface with the line chart, and initialize the serial
connection as we want to link the serial listener to the chart data.
23
24 this.getChildren().add(lineChart);
25
26 // Create an instance of the serial communications class
27 final Serial serial = SerialFactory.createInstance();
28
29 // Create and register the serial data listener
30 SerialListener serialListener = new SerialListener(data);
31 serial.addListener(serialListener);
32
33 this.startSerialCommunication(serial, serialDevice);
34
35 Thread t = new Thread(new SerialSender(serial));
36 t.start();
37 }
38
39 /**
40 * Start the serial communication
41 *
42 * @param serial Pi4J serial factory
43 * @param serialDevice the serial device
44 */
45 private void startSerialCommunication(Serial serial, String serialDevice) {
46 try {
47 // Create serial config object
48 SerialConfig config = new SerialConfig();
49 config.device(serialDevice)
50 .baud(Baud._38400)
51 .dataBits(DataBits._8)
52 .parity(Parity.NONE)
53 .stopBits(StopBits._1)
54 .flowControl(FlowControl.NONE);
55
56 // Display connection details
57 System.out.println("Connection: " + config.toString());
58
59 // Open the serial port with the configuration
60 serial.open(config);
61 } catch (Exception ex) {
62 System.err.println("Error: " + ex.getMessage());
63 }
64 }
65 }
Chapter 9: PI4J 243
Application code
OK, we have all the elements now! Let’s glue them together and start the application. The serial
device is the address we found in the “dmesg” log.
What’s next
The line chart can show different value sets. And the Arduino has a lot of analog and digital
connections. Check which components you have available, connect them to the Arduino, extend
the code and send their values as new types of data over the serial link.
By extending the SerialListener you can handle these different types and add them to additional
data sets.
Have fun! :-)
Chapter 9: PI4J 245
Very important remark before you power the test setup for this example! This module uses
5V so we don’t want it to send back data to the Pi GPIOs. This must be done by connecting
pin 5 (read/write) of the module to the ground.
We will be requesting the weather forecast from a public website to have dynamic data to visualize
on the LCD-display.
• VSS: ground
• VDD: 5V
• V0: with a variable resistor (potentiometer) connected to ground. Used to control the brightness
of the characters. If you don’t have such one, you can experiment with different resistors to
find the best one for maximum readability.
• RS, E, D4, D5, D6 and D7: to GPIO as defined in the code
Chapter 9: PI4J 246
• RW: ground. Blocks sending back data to the board as we don’t want to have 5V being sent to
the board.
• K: ground
• A: with a variable resistor connected to 5V. Similar to V0 controls the background-LED
brightness. This can also be replaced by a fixed resistor.
This is the final setup on my test board with the “Breadboard Pi Bridge”.
the “Price” page, you’ll see that only a small part can be used for free, but that’s still perfect for our
example!
Start by signing up and you’ll receive an AppId in your mailbox, for example, “Your API key is
9f72246c2183b3e577fb925fafa0cfbf”. This is the value to be filled in in the code. Based on the key,
the number of requests will be measured to check if you stay within the limits of the free account.
Let’s start with the forecast itself. We can build this as a separate class “WeatherRequest.java” which
only handles this single task and returns the String received from the API. The location and appId
are input parameters so we can easily test this in the next step.
Chapter 9: PI4J 248
1 /**
2 * Helper to get the forecast from OpenWeatherAPI.
3 */
4 public class WeatherRequest {
5 public static String getForecast(String location, String appId) {
6 StringBuilder rt = new StringBuilder();
7
8 try {
9 URL url = new URL("http://api.openweathermap.org/data/2.5/weather"
10 + "?units=metric"
11 + "&q=" + location
12 + "&appid=" + appId);
13
14 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
15 conn.setRequestMethod("GET");
16
17 int responseCode = conn.getResponseCode();
18 if (responseCode == HttpURLConnection.HTTP_OK) {
19 BufferedReader in = new BufferedReader(
20 new InputStreamReader(conn.getInputStream()));
21 String readLine;
22 while ((readLine = in.readLine()) != null) {
23 rt.append(readLine);
24 }
25 in.close();
26 } else {
27 System.err.println("Wrong response code: " + responseCode);
28 }
29 } catch (Exception ex) {
30 System.err.println("Request error: " + ex.getMessage());
31 }
32
33 return rt.toString();
34 }
35 }
To make sure this code works as expected, we use a unit test in the test “test/java”-directory. To make
this easy to maintain, the best practice is to use the same package-structure here as in “main/java”.
The test class has the same name as the class which is tested + “Test”. In this case, we create
“WeatherRequestTest.java” and check if we get a response from the weather service.
Chapter 9: PI4J 249
When we run this test, the result should be green and displaying the received forecast in the output.
The unit test from the previous step gives us a forecast in JSON format like this:
1 {
2 "coord":{
3 "lon":3.02,
4 "lat":50.9
5 },
6 "weather":[
7 {
8 "id":803,
9 "main":"Clouds",
10 "description":"broken clouds",
11 "icon":"04d"
12 }
13 ],
14 "base":"stations",
15 "main":{
16 "temp":6.16,
Chapter 9: PI4J 250
17 "feels_like":3.05,
18 "temp_min":3.89,
19 "temp_max":7.78,
20 "pressure":1032,
21 "humidity":87
22 },
23 "visibility":5000,
24 "wind":{
25 "speed":2.6,
26 "deg":70
27 },
28 "clouds":{
29 "all":75
30 },
31 "dt":1579779953,
32 "sys":{
33 "type":1,
34 "id":1233,
35 "country":"BE",
36 "sunrise":1579765021,
37 "sunset":1579796510
38 },
39 "timezone":3600,
40 "id":2794055,
41 "name":"Passchendaele",
42 "cod":200
43 }
To be able to use this data in our application, we need to convert it to a Java object and the library
“com.fasterxml.jackson.databind” will help us to achieve this.
First, we need to create the “Forecast.java” class to store every part of the data. As you can see every
value in this class is linked to a specific value from the Json data, e.g. “coord” will be mapped to the
coordinates variable.
Chapter 9: PI4J 251
And so on… As always you can find all the code as a finished project in the source code of this book
on GitHub.
To fill these objects from a JSON string, we create the class “WeatherMapper.java” which takes a
JSON String as input and returns a Forecast object:
Chapter 9: PI4J 252
1 /**
2 * Helper to convert the JSON received from OpenWeatherAPI to Java objects.
3 */
4 public class WeatherMapper {
5 public static Forecast getWeather(String jsonString) {
6 try {
7 ObjectMapper mapper = new ObjectMapper();
8 mapper.configure(
9 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
10 false);
11 return mapper.readValue(jsonString, Forecast.class);
12 } catch (IOException ex) {
13 System.err.println("Unable to parse the given string to object: "
14 + ex.getMessage());
15 return null;
16 }
17 }
18 }
At last, we add a unit test “WeatherMapperTest” to validate if an example JSON data string is
converted as expected. In the init we need the full JSON string (truncated for readability here),
and we create as many “@Test” functions as needed to check the parsing of all parts of the forecast.
21 ...
22 }
We will use a “Runnable” class to display the forecast output on the LCD-screen which will allow
us to run this in a “Thread”. This has the advantage it will keep updating the screen uncoupled from
the forecast request and we can implement functionality to continuously update the screen.
All this is integrated in “LcdOutput.java”. We start with some variables we will need later, a
constructor with the “GpioLcdDisplay” as a parameter and a method to receive the “Forecast”. There
is also a getter for the running state, so we can decide in the “main” class if the application needs to
keep running.
1 /**
2 * Runnable class to continuously update the LCD-display with weather info.
3 */
4 public class LcdOutput implements Runnable {
5 private static final int LCD_ROW_1 = 0;
6 private static final int LCD_ROW_2 = 1;
7 private static final int CONTENT_INTERVAL = 2500;
8
9 private final GpioLcdDisplay lcd;
10
11 private boolean running = false;
12 private Forecast forecast = null;
13 private long lastUpdate = 0;
14 private int contentStep = 0;
15
16 private SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
17
18 /**
19 * Constructor
20 *
21 * @param lcd Link to the GpioLcdDisplay
22 */
23 public LcdOutput(GpioLcdDisplay lcd) {
24 this.lcd = lcd;
25 }
26
27 /**
28 * Update the forecast used to show data on the LCD
29 *
Chapter 9: PI4J 254
As this class implements “Runnable”, we need to add a run-method which will be called if this is
started in a “Thread” which we will see later. This keeps running (except when an error occurs) and
calls the “showContent” method on a predefined interval variable “CONTENT_INTERVAL” which
was already defined as 2500 milliseconds.
1 /**
2 * Method started by the tread which keeps looping until an error happens.
3 * On pre-defined interval, showContent is called to update the LCD output.
4 */
5 @Override
6 public void run() {
7 this.running = true;
8
9 try {
10 while (this.running) {
11 if (this.forecast != null
12 && (System.currentTimeMillis() - this.lastUpdate)
13 > CONTENT_INTERVAL) {
14 this.showContent();
15 this.lastUpdate = System.currentTimeMillis();
16 }
17
18 Thread.sleep(100);
19 }
20 } catch (Exception ex) {
21 System.err.println("Error in LCD output thread: " + ex.getMessage());
22
23 this.running = false;
Chapter 9: PI4J 255
24 }
25 }
Within the “showContent” method we handle the cycling of the content with the “contentStep”
variable. If you want to add extra output, this is the place to be…
1 /**
2 * Periodically change the content on the LCD in different steps.
3 */
4 public void showContent() {
5 switch (this.contentStep) {
6 case 0:
7 this.showTimestamp();
8 break;
9 case 1:
10 this.showTemperatures();
11 break;
12 case 2:
13 this.showDescription();
14 break;
15 default:
16 System.err.println("Step not defined");
17 }
18
19 this.contentStep++;
20
21 if (this.contentStep > 2) {
22 this.contentStep = 0;
23 }
24 }
And of course, we now need to create the code for each of these methods which show a specific
part of the forecast on the LCD-Screen. This is the code for the temperature output, you can find the
other ones in the source code.
Chapter 9: PI4J 256
1 /**
2 * Show the forecast temperatures.
3 */
4 private void showTemperatures() {
5 System.out.println("Showing temperature " + forecast.weatherInfo.temperature);
6
7 try {
8 lcd.clear();
9 Thread.sleep(1000);
10
11 lcd.write(LCD_ROW_1, "Temp",
12 LCDTextAlignment.ALIGN_LEFT);
13 lcd.write(LCD_ROW_1, String.valueOf(forecast.weatherInfo.temperature),
14 LCDTextAlignment.ALIGN_RIGHT);
15 lcd.write(LCD_ROW_2, "Min/Max "
16 + String.valueOf(forecast.weatherInfo.temperatureMinimum)
17 + "/"
18 + String.valueOf(forecast.weatherInfo.temperatureMaximum),
19 LCDTextAlignment.ALIGN_CENTER);
20 } catch (Exception ex) {
21 System.err.println("Error while handling content for the LCD: "
22 + ex.getMessage());
23 }
24 }
This is a long class, but by splitting up into multiple smaller methods, it’s still very readable and
easy to extend. As always, this is just one example, feel free to play with it and put on the screen
whatever you want…
Now we have all the building blocks to glue this together to one application in the “App.java” class
and “main” method. This method will run in the first (main) thread.
We first initialize “GpioController” and “GpioLcdDisplay” from Pi4J. Then we can initialize our
“LcdOutput” with the already created “GpioLcdDisplay” as a parameter and can start running it in
a new (second) thread.
As a result, the App-class and the LcdOutput-class will run next to each other, so they can do their
stuff without blocking the other one. And that’s what we use by looping in the main-method to
request a new forecast every number of seconds defined by REQUEST_FORECAST_SECONDS.
But when an error happened in LcdOutput and it’s not running anymore, we also stop the loop here
and the application will exit.
Chapter 9: PI4J 257
44 while (lcdOutput.isRunning()) {
45 apiReply = WeatherRequest.getForecast(LOCATION, APP_ID);
46 if (!apiReply.isEmpty()) {
47 System.out.println("Received: " + apiReply);
48 lcdOutput.setForecast(WeatherMapper.getWeather(apiReply));
49 } else {
50 System.err.println("Could not get forecast");
51 }
52
53 Thread.sleep(REQUEST_FORECAST_SECONDS * 1000L);
54 }
55
56 // Shut down the GPIO controller
57 gpio.shutdown();
58
59 System.out.println("Done");
60 } catch (Exception ex) {
61 System.err.println("Error: " + ex.getMessage());
62 }
63 }
64 }
First “Started…” and “Java VERSION” will be shown on the LCD as defined in the main-method, but
as soon as a forecast is received, the output generated by LcdOutput will be on the screen.
Chapter 9: PI4J 259
While testing this example on another day, an expected output on the temperature screen
appeared with “4emp” where it should be displaying “Temp”.
Apparently, when the text is too long for one line, it overflows on the other line and the
length of the string value needs to be checked before sending it to the LCD. We can use the
“substring(beginIndex, endIndex)” method to achieve this, as displayed here with a test in
“jshell”:
Conclusion
In this example, you learned how easy it is to get data from a public source and show it on the
LCD. Of course, you could also show a sensor measurement or a database value or … Again, your
imagination is the only limit!
Just a thought: Switching social
I have to admit, yes, I’m socially addicted. Although I’m not the person who starts talking to everyone
in real life. But on-line I’m networking fulltime with all means. I probably had an account on every
service you can think of.
Twitter, Facebook, Google, LinkedIn and every new thing which seemed interesting for one or more
reasons… Until a few years ago, when you were searching for test-users and I saw your tweet, you
got my data within five minutes.
Free is not Free
Of course, I realized a long time ago those services are free because they make a profit with your
data. Your data is the oil that keeps their engine running. Google offers you all those user-friendly
tools because they get to know you thanks to your gmails, documents in Google Drive, browsing and
location history… And because of that, they can show you advertisements based on your interests
so there is a bigger chance you click on them, buy and make the Google cash flow. That’s also how
Facebook knows your relation will end long before you change your status to “it’s complicated”
yourself. And LinkedIn knows you’re searching for a new job, long before you request a final chat
with your boss.
But what applies on-line, also happens off-line. Supermarkets know you’re pregnant thanks to your
card, based on your changed shopping habits, before you even tell your parents.
So we are constantly monitored and categorized, without seeing, and pushed in the most affordable
direction for the advertisers.
You are being sold
But it’s not that bad, isn’t it? That’s also what I thought. Until I saw the talks of Aral Balkan. Years
ago I saw him the first time at Multi-Mania in Kortrijk where he talked about user experience design
and especially how dark-pattern-designs are used to trick users in choosing the most expensive
option (low-cost flight operators seem to be most experienced in this matter…). Shortly after, he
changed in an even more inspiring speaker, fighting for a new internet where the user becomes the
owner of his own digital identity. He and his wife Laura Kalbag, who is an even important voice in
the same battle, founded the Small Technology foundation which advocates for, and builds small
technology to protect personhood and democracy in the digital network age.
It’s no longer only advertising we have to worry about. That whole system to get to know as much
as possible about you has only one goal: sell your identity, a digital copy of you. If you don’t pay for
a service, you are the one being sold. You became the product being sold. You are being farmed!
The acronym TANSTAAFL (There ain’t no such thing as a free lunch already exists since the 1930s,
but it has taken a very bad turn in the last decade.
Rehab
Just a thought: Switching social 261
1 @Component
2 public class SensorDao {
3 // We use the generic abbreviation for this class: DAO = Data Access Object
4 public List<Sensor> getSensors() {
5 // Database code needs to be added here
6 }
7 }
Now any other class in the application can use this Component by auto-wiring to it, without the
need to initialize it or worry about the correct order of initialization.
¹⁰⁵https://micronaut.io/
¹⁰⁶https://quarkus.io/
¹⁰⁷https://pivotal.io/
¹⁰⁸https://en.wikipedia.org/wiki/Inversion_of_control
¹⁰⁹https://en.wikipedia.org/wiki/Plain_old_Java_object
Chapter 10: Spring 263
1 @Component
2 public class HtmlHelper {
3 @Autowired
4 private SensorDao sensorDao;
5
6 public String getSensorsAsHtmlList() {
7 StringBuilder rt = new StringBuilder();
8 rt.append("<ul>");
9 for (Sensor sensor : this.sensorDao.getSensors()) {
10 rt.append("<li>").append(sensor.getName()).append("</li>");
11 }
12 rt.append("<ul>");
13 return rt.toString();
14 }
15 }
At startup, the framework will make sure the SensorDao is available for HtmlHelper when it needs
it.
Chapter 10: Spring 264
The Spring examples in this book are all based on Spring Boot.
¹¹⁰https://spring.io/projects/spring-boot
Chapter 10: Spring 265
Spring Initializr
Click on the “Generate” button and you will get a ZIP-file with a ready-to-use Maven project.
The unmodified downloaded sources from start.spring.io are included in the sources of this
book:
Chapter_10_Spring > java-spring-rest-original
This project can be opened in Visual Studio Code and started by hitting the Run command in
JavaSpringRestApplication.java
¹¹¹https://start.spring.io/
¹¹²https://en.wikipedia.org/wiki/Representational_state_transfer
Chapter 10: Spring 266
In the logging we will get this result (without the timestamps here for readability):
1 . ____ _ __ _ _
2 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
3 ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
4 \\/ ___)| |_)| | | | | || (_| | ) ) ) )
5 ' |____| .__|_| |_|_| |_\__, | / / / /
6 =========|_|==============|___/=/_/_/_/
7 :: Spring Boot :: (v2.2.2.RELEASE)
8
9 Starting JavaSpringRestApplication with PID 1260
10 (C:\...\java-spring-rest-original\target\classes
11 started by Frank in C:\...\java-spring-rest-original)
12 No active profile set, falling back to default profiles: default
13 Tomcat initialized with port(s): 8080 (http)
14 Starting service [Tomcat]
15 Starting Servlet engine: [Apache Tomcat/9.0.29]
16 Initializing Spring embedded WebApplicationContext
17 Root WebApplicationContext: initialization completed in 1607 ms
18 Initializing ExecutorService 'applicationTaskExecutor'
19 Tomcat started on port(s): 8080 (http) with context path ''
20 Started JavaSpringRestApplication in 4.582 seconds (JVM running for 7.196)
21 Initializing Spring DispatcherServlet 'dispatcherServlet'
22 Initializing Servlet 'dispatcherServlet'
23 Completed initialization in 9 ms
• JVM is running for 7 seconds of which 5 seconds was needed to start the application.
• Tomcat (the webserver) is embedded in the application and running on port 8080.
Chapter 10: Spring 267
An error page? Indeed, we didn’t create anything yet to be on this page! But as we get this error
page, we know our application is working and acting as a webserver. It just doesn’t know yet what
to give us back.
Let’s extend this “empty box” with some nice features we can use on the Pi in the next examples.
Chapter 10: Spring 268
It’s also an incredibly versatile language with a massive number of libraries available - many
of which are free and open-source - to solve established problems & brand new ones, making a
developer’s job much easier and more enjoyable. It’s like having a never-ending toolbox of options
at hand, for a language that’s constantly adding capabilities. What could be better than that???
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
I’m building a real-world distributed system with live aviation data streams using the Raspberry
Pi and other small devices. I plan to showcase that in my upcoming book, “Spring Boot: Up &
Running!”, due later this year. As you might expect, Spring Boot & other Spring portfolio projects
feature heavily in that. I’m really excited about it!
https://twitter.com/mkheck
https://spring.io/
https://start.spring.io/
Chapter 10: Spring 270
1 <groupId>be.webtechie</groupId>
2 <artifactId>java-spring-image-server</artifactId>
3 <version>0.0.1-SNAPSHOT</version>
4 <name>java-spring-image-server</name>
5 <description>Spring Boot project to access pictures via the browser</description>
We also add some dependencies which will help us to test our application with Swagger¹¹³. This
framework will automatically provide documentation webpages for all our web services.
1 <dependencies>
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-web</artifactId>
5 </dependency>
6
7 <dependency>
8 <groupId>io.springfox</groupId>
9 <artifactId>springfox-swagger2</artifactId>
10 <version>2.9.2</version>
11 </dependency>
12 <dependency>
13 <groupId>io.springfox</groupId>
14 <artifactId>springfox-swagger-ui</artifactId>
¹¹³https://swagger.io/
Chapter 10: Spring 271
15 <version>2.9.2</version>
16 </dependency>
17
18 <dependency>
19 <groupId>org.springframework.boot</groupId>
20 <artifactId>spring-boot-starter-test</artifactId>
21 <scope>test</scope>
22 </dependency>
23 </dependencies>
Application properties
We will use a Spring property to make it easy to change the directory where the images are stored.
Open the file “application.properties” from the resources directory. Create a directory on your PC
with some test images and add the path to this file.
On Windows, directories are separated with a backslash, but we need to use a double one for correct
parsing of this value, as you can see in the screenshot.
application.properties file
The second line in this screenshot is a comment (starts with “#”) and is the value we are going to
use for this property when we’ve finished testing and want to build this application for the Pi. At
that moment we move the “#” to the first line with the Windows setting.
Image controller
And now we are going to add the image controller which needs to do two things: show a list of all
the available images and provide a selected image. Again we add a new package “controller” and
add a file “ImageController.java”. This is the initial code for this file which will generate a table
with the files in the directory which is configured in the application.properties file with the key
“path.images”.
Chapter 10: Spring 272
Note a StringBuilder is used to construct the HTML table. This will work a lot faster compared to
the use of a String. The extra whitespace and tabs in the different “.append” lines are only there for
better readability.
1 /**
2 * REST-calls to access the images on this device.
3 */
4 @RestController
5 public class ImageController {
6 /**
7 * Get the value from application.properties where we define
8 * the location of the images.
9 */
10 @Value("${path.images}")
11 private String pathImages;
12
13 /**
14 * Get a list of all the files.
15 * @return An HTML string with a list of all the files.
16 */
17 @GetMapping("/files")
18 public String getFiles() {
19 StringBuilder rt = new StringBuilder();
20
21 try {
22 rt.append("<html>")
23 .append(" <body>")
24 .append(" <table>")
25 .append(" <tr>")
26 .append(" <th>File</th>")
27 .append(" <th>Size</th>")
28 .append(" <th>Date</th>")
29 .append(" <tr>");
30
31 File[] childFiles = (new File(this.pathImages)).listFiles();
32 for (File childFile : childFiles) {
33 String relativePath = childFile.getName();
34 rt.append(" <tr>")
35 .append(" <td>")
36 .append("<a href='file/")
37 .append(URLEncoder.encode(relativePath, "UTF-8"))
38 .append("' target='_blank'>")
39 .append(relativePath)
Chapter 10: Spring 273
40 .append("</a></td>")
41 .append(" <td style='text-align: right;'>")
42 .append(getSize(childFile)).append("</td>")
43 .append(" <td>")
44 .append(getTimestamp(childFile)).append("</td>")
45 .append(" </tr>");
46 }
47
48 rt.append(" <table>");
49 rt.append(" </body>");
50 rt.append("</html>");
51
52 } catch (Exception ex) {
53 throw new RuntimeException("Error accessing requested file/directory: "
54 + ex.getMessage());
55 }
56
57 return rt.toString();
58 }
59
60 /**
61 * Converts the file size in bytes to Kb.
62 *
63 * @param file
64 * @return
65 */
66 private String getSize(File file) {
67 long sizeInBytes = file.length();
68 long sizeInKilobytes = sizeInBytes / 1024;
69 return sizeInKilobytes + "Kb";
70 }
71
72 /**
73 * Converts the last modified timestamp of the file to a readable format.
74 *
75 * @param file
76 * @return
77 */
78 private String getTimestamp(File file) {
79 long timestamp = file.lastModified();
80 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
81 return dateFormat.format(new Date(timestamp));
82 }
Chapter 10: Spring 274
83 }
Now let’s add a second method to get the file itself. Some more code is needed here to make sure
the file exists and we return the correct media type depending on the type of image.
1 /**
2 * Get the request file.
3 * @param fileName The filename
4 * @return The file as byte array
5 */
6 @GetMapping(
7 value = "/file/{filename}",
8 produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
9 public ResponseEntity<byte[]> getFile(@PathVariable("filename") String fileName) {
10 // Initiate the headers we will use in the return
11 HttpHeaders headers = new HttpHeaders();
12 headers.setCacheControl(CacheControl.noCache().getHeaderValue());
13
14 // Get the file
15 File file = new File(this.pathImages, fileName);
16
17 // Check if the file exists.
18 if (!file.exists()) {
19 // Immediately return error 404.
20 return new ResponseEntity(HttpStatus.NOT_FOUND);
21 }
Chapter 10: Spring 275
22
23 // Get the file as a byte array.
24 byte[] media = null;
25 try (InputStream in = new FileInputStream(file)) {
26 media = in.readAllBytes();
27 } catch (IOException ex) {
28 // Oops something went wrong, return error 500.
29 headers.setContentType(MediaType.TEXT_PLAIN);
30 return new ResponseEntity(ex.getMessage(), headers,
31 HttpStatus.INTERNAL_SERVER_ERROR);
32 }
33
34 // Check which type of file we are returning so we can correctly define
35 // the header content type. By doing this, the browser can show
36 // the image inside the browser, otherwise it will do a download.
37 if (fileName.toLowerCase().endsWith(".jpg")) {
38 headers.setContentType(MediaType.IMAGE_JPEG);
39 } else if (fileName.toLowerCase().endsWith(".png")) {
40 headers.setContentType(MediaType.IMAGE_PNG);
41 } else if (fileName.toLowerCase().endsWith(".gif")) {
42 headers.setContentType(MediaType.IMAGE_GIF);
43 }
44
45 // Everything OK, return the image.
46 return new ResponseEntity<>(media, headers, HttpStatus.OK);
47 }
If you want to extend this web-interface with more pages with a nicer look-and-feel, you
should take a look at Thymeleaf¹¹⁴. This server-side Java template engine, allows you to
separate HTML files from code. This results in cleaner code and easier to maintain web
pages.
Swagger config
To configure Swagger, we need to add a class. For a clear structure, it is added in a new package
“configuration” with the file “SwaggerConfig.java” which looks like this to automatically document
all our web services:
1 @Configuration
2 @EnableSwagger2
3 public class SwaggerConfig {
4 @Bean
5 public Docket api() {
6 return new Docket(DocumentationType.SWAGGER_2)
7 .select()
8 .apis(RequestHandlerSelectors.any())
9 .paths(PathSelectors.any())
10 .build();
11 }
12 }
This simple config will automatically create a webpage with all the info of the web services we
created in our application on “localhost:8080/swagger-ui.html”.
¹¹⁴https://www.thymeleaf.org/
Chapter 10: Spring 277
Swagger UI
Run on the Pi
Change the application.properties file to define a directory on your Pi from which the images must
be loaded, for example:
application.properties for Pi
Now build the application with “mvn clean package” and copy the file “java-spring-image-server-
0.0.1-SNAPSHOT.jar” from the target directory to your Pi. Start the application with “java -jar java-
spring-image-server-0.0.1-SNAPSHOT.jar” and browse with your PC to the IP of your Pi, e.g. in my
case on “http://192.168.0.223:8080/files”:
Chapter 10: Spring 278
Conclusion
And there it is, our image server! Start with an empty Spring project, add one class (Swagger is not
really needed, it’s only here as an example) and done!!!
Chapter 10: Spring 279
The H2 database¹¹⁵ we will be using is a full-Java-solution which doesn’t need any additional
installation but is fully part of the application itself.
There is a lot of “discussion” whether you should use H2 only for testing or can use it in production.
In recent years it has evolved into a very stable database solution which in my opinion is a very
good choice for embedded projects.
JPA is the persistence specification used to “communicate” with the database. It helps you to define
which objects (entities) can be stored in a database in which structure (tables).
pom.xml settings
Again starting from a minimal Spring project, we modify the pom.xml file with the correct settings
and some more dependencies.
1 <groupId>be.webtechie</groupId>
2 <artifactId>java-spring-rest-db</artifactId>
3 <version>0.0.1-SNAPSHOT</version>
4 <name>java-spring-rest-db</name>
5 <description>Spring Boot project to store data in a H2 database</description>
6
7 <dependencies>
8 <dependency>
9 <groupId>org.springframework.boot</groupId>
10 <artifactId>spring-boot-starter-web</artifactId>
11 </dependency>
12 <dependency>
13 <groupId>org.springframework.boot</groupId>
14 <artifactId>spring-boot-starter-data-jpa</artifactId>
15 </dependency>
16 <dependency>
17 <groupId>org.springframework.boot</groupId>
18 <artifactId>spring-boot-starter-data-rest</artifactId>
¹¹⁵https://www.h2database.com
Chapter 10: Spring 280
19 </dependency>
20 <dependency>
21 <groupId>com.h2database</groupId>
22 <artifactId>h2</artifactId>
23 <scope>runtime</scope>
24 </dependency>
25
26 <dependency>
27 <groupId>io.springfox</groupId>
28 <artifactId>springfox-swagger2</artifactId>
29 <version>2.9.2</version>
30 </dependency>
31 <dependency>
32 <groupId>io.springfox</groupId>
33 <artifactId>springfox-swagger-ui</artifactId>
34 <version>2.9.2</version>
35 </dependency>
36
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-test</artifactId>
40 <scope>test</scope>
41 </dependency>
42 </dependencies>
• Sensor
• Unlimited number of measurements per sensor
This can be achieved by adding two classes to our project in a package (directory) “entity”. First,
we create one for the sensors called “SensorEntity.java”. As you can see this code contains a lot of
“annotations” (start with @) which will help the framework to map the code to the database.
1 /**
2 * Maps a database entity from the table SENSORS to a Java object.
3 * The ID is marked as the unique identifier.
4 */
5 @Entity
6 @Table(name = "SENSORS",
7 uniqueConstraints={@UniqueConstraint(
8 name="UN_SENSOR_ID",
9 columnNames={"ID"})})
10 public class SensorEntity {
11 /**
12 * Auto-generated identifier to have a unique key for this sensor.
13 */
14 @Id
15 @GeneratedValue
16 private Long id;
17
18 /**
19 * Name of the sensor, a required value.
20 */
21 @Column(nullable = false)
22 private String name;
23
24 /**
25 * Relationship between the sensor and a list of measurements.
26 */
27 @OneToMany(
28 mappedBy = "sensorEntity",
29 cascade = {CascadeType.MERGE},
30 fetch = FetchType.LAZY
Chapter 10: Spring 282
31 )
32 private Set<MeasurementEntity> measurements = new HashSet<>();
33
34 /**
35 * No-argument constructor is needed for JPA.
36 */
37 public SensorEntity() {
38 // NOP
39 }
40
41 /**
42 * Constructor with a name value.
43 * @param name
44 */
45 public SensorEntity(String name) {
46 this.name = name;
47 }
48
49 // Getters and setters needed by JPA and the code.
50 public Long getId() {
51 return id;
52 }
53
54 public void setId(Long id) {
55 this.id = id;
56 }
57
58 public String getName() {
59 return name;
60 }
61
62 public void setName(String name) {
63 this.name = name;
64 }
65
66 public Set<MeasurementEntity> getDataEntries() {
67 return measurements;
68 }
69
70 public void setDataEntries(Set<MeasurementEntity> dataEntries) {
71 this.measurements = dataEntries;
72 }
73 }
Chapter 10: Spring 283
1 /**
2 * Maps a database entity from the table MEASUREMENTS to a Java object.
3 * The ID is marked as the unique identifier.
4 */
5 @Entity
6 @Table(name = "MEASUREMENTS",
7 uniqueConstraints={@UniqueConstraint(
8 name="UN_MEASUREMENT_ID",
9 columnNames={"ID"})})
10 public class MeasurementEntity {
11
12 /**
13 * Auto-generated identifier to have a unique key for this sensor.
14 */
15 @Id
16 @GeneratedValue
17 private Long id;
18
19 /**
20 * Relationship between the measurement and its sensor.
21 */
22 @ManyToOne
23 @JoinColumn(
24 name = "SENSOR_ID",
25 nullable = false,
26 foreignKey = @ForeignKey(name="FK_MEASUREMENT_SENSOR"))
27 private SensorEntity sensorEntity;
28
29 /**
30 * Timestamp of the measurement.
31 */
32 @Column(nullable = false)
33 private long timestamp;
34
35 /**
36 * Key for the type of measurement, e.g. "temperature", "distance"...
37 */
38 @Column(nullable = false)
39 private String key;
40
41 /**
Chapter 10: Spring 284
Notice the “@JsonIgnore” on “getSensor()” in this entity class. It’s added here to avoid
endless loops when we load the data with the REST-service. Otherwise, the application tries
to nest measurements-with-sensors into sensors-with-measurements resulting in this error:
These two classes are all we need to define the database tables and how data needs to be stored!
1 @Repository
2 public interface SensorRepository extends JpaRepository<SensorEntity, Long>{
3 Page<SensorEntity> findAll(Pageable pageable);
4
5 List<SensorEntity> findAllByName(String name);
6
7 SensorEntity findById(@Param("id") long id);
8 }
1 @Repository
2 public interface MeasurementRepository extends
3 JpaRepository<MeasurementEntity, Long>{
4 Page<MeasurementEntity> findAll(Pageable pageable);
5 }
Create a package “resource” and a file “SensorResource.java”. In here we define three services which
will be available on an URL:
1 @RestController
2 public class SensorResource {
3 @Autowired
4 private SensorRepository sensorRepository;
5
6 @GetMapping("/sensor")
7 public List<SensorEntity> retrieveAllSensors() {
8 return sensorRepository.findAll();
9 }
10
11 @GetMapping("/sensor/{id}")
12 public SensorEntity retrieveSensor(@RequestParam long id) {
13 return sensorRepository.findById(id);
14 }
15
16 @PostMapping("/sensor")
17 public ResponseEntity createSensor(@RequestParam String name) {
18 List<SensorEntity> sensorEntities = sensorRepository.findAllByName(name);
19
20 if (sensorEntities.size() > 0) {
21 return ResponseEntity.status(HttpStatus.BAD_REQUEST)
22 .body("There is already a sensor with the name: " + name);
23 }
24
25 SensorEntity sensorEntity = new SensorEntity(name);
26 sensorRepository.save(sensorEntity);
27 return ResponseEntity.ok(sensorEntity);
28 }
29 }
• POST localhost:8080/measurement: add a measurement for the given sensor ID, key and value,
after checking the given sensor ID is defined in the database:
1 @RestController
2 public class MeasurementResource {
3 @Autowired
4 private SensorRepository sensorRepository;
5
6 @Autowired
7 private MeasurementRepository measurementRepository;
8
9 @GetMapping("/measurement")
10 public List<MeasurementEntity> retrieveAllMeasurements() {
11 return measurementRepository.findAll();
12 }
13
14 @PostMapping("/measurement")
15 public ResponseEntity createMeasurement(
16 @RequestParam long sensorId,
17 @RequestParam String key,
18 @RequestParam double value) {
19
20 SensorEntity sensorEntity = sensorRepository.findById(sensorId);
21
22 if (sensorEntity == null) {
23 return ResponseEntity.status(HttpStatus.BAD_REQUEST)
24 .body("No sensor defined with the ID: " + sensorId);
25 }
26
27 MeasurementEntity measurementEntity = new MeasurementEntity(
28 sensorEntity, System.currentTimeMillis(), key, value);
29 measurementRepository.save(measurementEntity);
30
31 return ResponseEntity.ok().build();
32 }
33 }
Adding Swagger
One final coding step, so we can use Swagger to quickly test our application! Create a package
“configuration” with the file “SwaggerConfig.java” to expose our REST-resources:
Chapter 10: Spring 288
1 @Configuration
2 @EnableSwagger2
3 public class SwaggerConfig {
4 @Bean
5 public Docket api() {
6 return new Docket(DocumentationType.SWAGGER_2)
7 .select()
8 .apis(RequestHandlerSelectors.any())
9 .paths(PathSelectors.any())
10 .build();
11 }
12 }
Let’s start by creating some sensors by clicking on “POST /sensor” and “Try it out”. Fill in some
values (e.g. “temp1”, “temp2”…) and each time hit “Execute”.
Chapter 10: Spring 289
If you try to add the same name twice, an error will be returned:
Now you can see the created records in Swagger by trying out the GET’s for “/sensor” and “/sensor/”,
but also by browsing directly to http://localhost:8080/sensor. The data is formatted in this screenshot
of Firefox with the “JSON-formatter” plugin:
Next step: storing some measurements for one of our sensors (ID 1):
Chapter 10: Spring 290
If you add an additional setting in “src > main > resources > application.properties” something
magical happens. Out of the blue, our application is extended with a full database browser!
1 spring.h2.console.enabled=true
Restart your application so the new setting is applied. Because H2 by default stores everything in
memory, our test data is gone, and we need to first generate some again with Swagger as described
Chapter 10: Spring 291
After login we see the database structure as we defined it in our code for both tables:
1 $ mkdir /home/pi/dbapp
2 $ cd /home/pi/dbapp
3 $ mkdir config
4 $ nano config/application.properties
5
6 spring.datasource.url=jdbc:h2:file:/home/pi/dbapp/spring-boot-h2-db
7 spring.datasource.username=sa
8 spring.datasource.password=
9 spring.datasource.driver-class-name=org.h2.Driver
10 spring.jpa.hibernate.ddl-auto=update
Build the application on your PC to a jar with “mvn clean package” and copy “java-spring-rest-db-
0.0.1-SNAPSHOT.jar” from the “target” directory to your Pi in the “/home/pi/dbapp” directory.
In this screenshot, you also see the created database file “spring-boot-h2-db.mv.db” as defined in the
properties file. When adding data via Swagger, you will see the size of this file grow.
Running the application gives the expected output similar to the one on the PC:
The big difference is this last line when compared to my development PC:
Indeed you’ll need to take into account this application needs a longer start-up time on the Pi. But
as soon as it runs, you can access Swagger and the REST-services from any PC within your network
on the IP address of your Pi, in my case 192.168.0.223:
Chapter 10: Spring 294
Conclusion
Just a basic example with two tables, but it shows you how quickly and with minimal code, a
database application can be built. The REST-services are available to all your devices who can
connect to your Pi via the network so they can store data in one central place and/or can read
that data.
The JSON data provided by the REST-services can be used by all different kinds of devices or
applications to visualize the results. On the Elektor website you can find a nice example of a
microcontroller doing this to show JSON data on a screen¹¹⁶.
¹¹⁶https://www.elektormagazine.com/labs/9292-dutch-public-transport-monitor
Chapter 10: Spring 295
The new development cycle of Java, with a release every 6 months, allows the Java and JDK
developers to introduce many useful features. And, there are also many great features to come,
like Project Loom or Valhalla.
Why is now the perfect time to learn Java?
Because Java has a rich ecosystem of open-source frameworks and being able to run it on a great
variety of systems, ranging from small devices to supercomputers, Java and the JVM are a great
choice.
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
Hypersistence Optimizer is what I’m currently working on, and I’m very excited about it as it allows
you to automate the process of detecting JPA and Hibernate issues, so you can finally focus on data
access logic instead of chasing performance-related issues.
https://twitter.com/vlad_mihalcea
https://vladmihalcea.com/books/high-performance-java-persistence/
https://github.com/vladmihalcea/hibernate-types
https://vladmihalcea.com/hypersistence-optimizer/
Project Loom wants to make it easier to write, debug, profile and maintain concurrent Java applications.
Project Valhalla combines multiple sub-projects aiming to adapt the Java language and runtime to modern hardware.
https://vladmihalcea.com/hypersistence-optimizer/
Chapter 10: Spring 297
We start from the minimal Spring sources again and need to add this dependency:
1 <dependency>
2 <groupId>com.pi4j</groupId>
3 <artifactId>pi4j-core</artifactId>
4 <version>1.2</version>
5 <scope>compile</scope>
6 </dependency>
Info REST-controller
The first thing we are going to expose with this application, is the information provided by the Pi4J
library.
Create a package “controller” with a file “InfoRestController.java”. In the sources, you can find the
full code, but this is a short piece. Each method is a REST-mapping which returns a specific set of
key-value pairs with info about your Raspberry Pi.
1 /**
2 * Provides a REST-interface to expose all board info.
3 *
4 * Based on https://pi4j.com/1.2/example/system-info.html
5 */
6 @RestController
7 @RequestMapping("info")
8 public class InfoRestController {
9 private Logger logger = LoggerFactory.getLogger(this.getClass());
10
11 /**
12 * Get the OS info.
13 */
14 @GetMapping(path = "os", produces = "application/json")
Chapter 10: Spring 298
GPIO Manager
Before we can start creating the GPIO REST-controller, we will add GpioManager which handles
the Pi4J calls. We will use this manager to store the initialized GPIO pins and call the Pi4J methods
to interact with the GPIOs. Check the sources for the full class.
Chapter 10: Spring 299
1 /**
2 * Singleton instance for the {@link GpioFactory}.
3 * SCOPE_SINGLETON is the default value, but added for clarity.
4 */
5 @Component
6 @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
7 public class GpioManager {
8 private Logger logger = LoggerFactory.getLogger(this.getClass());
9
10 /**
11 * The GPIO controller.
12 */
13 private final GpioController gpio;
14
15 /**
16 * List of the provisioned pins with the address as key.
17 */
18 private final Map<Integer, Object> provisionedPins = new HashMap<>();
19
20 /**
21 * Constructor which initializes the Pi4J {@link GpioController}.
22 */
23 public GpioManager() {
24 this.gpio = GpioFactory.getInstance();
25 }
26
27 /**
28 * Get the pin for the given address.
29 *
30 * @param address The address of the GPIO pin.
31 * @return The {@link Pin} or null when not found.
32 */
33 private Pin getPinByAddress(int address) {
34 Pin pin = RaspiPin.getPinByAddress(address);
35 if (pin == null) {
36 logger.error("No pin available for address {}", address);
37 }
38 return pin;
39 }
40
41 /**
42 * Provision a GPIO as digital output pin.
43 *
Chapter 10: Spring 300
GPIO REST-controller
Let’s add a controller to expose the Pi4J GPIO-methods we integrated in the GpioManager.java class.
Below only a few of the methods are included, you can find all of them in the sources:
1 /**
2 * Provides a REST-interface with the pins.
3 */
4 @RestController
5 @RequestMapping("gpio")
6 public class GpioRestController {
7 private Logger logger = LoggerFactory.getLogger(this.getClass());
8
9 private final GpioManager gpioManager;
10
11 public GpioRestController(GpioManager gpioManager) {
12 this.gpioManager = gpioManager;
13 }
14
15 ...
16
17 /**
18 * Provision a GPIO as digital output pin.
19 *
20 * @param address The address of the GPIO pin.
21 * @param name The name of the GPIO pin.
22 * @return True if successful.
23 */
24 @PostMapping(
25 path = "provision/digital/output/{address}/{name}",
26 produces = "application/json")
27 public boolean provisionDigitalOutputPin(@PathVariable("address") int address,
28 @PathVariable("name") String name) {
Chapter 10: Spring 302
Wiring on a breadboard
Browse to your Pi to the Swagger page from any PC in the same network and you will see the two
controllers with the methods listed here:
Swagger info-controller
Swagger GPIO-controller
We can click on the Swagger page and execute one of the available options, but let’s try an info
method by going to the URL directly. These are some of the results on a fresh new Raspbian 3B+
board:
Chapter 10: Spring 304
To be able to control the connected LED and read out the button state, we first need to initialize the
GPIOs. This can be done with two dedicated methods in the GPIO controller and using the WiringPi
numbers:
Chapter 10: Spring 305
As we checked the GPIOs are ready to use, we can now toggle the LED on and off by clicking on
the “Execute”-button again and again:
There is also an additional method to put the LED on for a given time, in this example 2 seconds,
Chapter 10: Spring 306
Requesting the state of the button can be done via Swagger but also directly via the URL. In this
case, the button is pressed and returns 1:
Conclusion
This application only exposes a few of the Pi4J methods as a REST-service to show the possibilities
and power of this approach. Depending on the project you want to build, you can extend or rework
this example to fit your exact needs.
Chapter 10: Spring 307
The code
This project uses three classes in this structure:
¹¹⁷https://en.wikipedia.org/wiki/Reactive_programming
¹¹⁸https://twitter.com/starbuxman
¹¹⁹https://trishagee.github.io/presentation/coding_duel/
Chapter 10: Spring 308
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-webflux</artifactId>
4 </dependency>
This object will be used to push data into the stream every second.
1 package be.webtechie.javaspringstream.dto;
2
3 /**
4 * Object containing a distance measurement.
5 */
6 public class DistanceMeasurement {
7 private final long timestamp;
8 private final int distance;
9 private final float duration;
10
11 /**
12 * Constructor which will add the current timestamp.
13 *
14 * @param distance The distance in centimeter
15 * @param duration The measurement duration in nanos
16 */
17 public DistanceMeasurement(int distance, float duration) {
18 this.timestamp = System.currentTimeMillis();
19 this.distance = distance;
20 this.duration = duration;
21 }
22
23 public long getTimestamp() {
24 return timestamp;
25 }
26
27 public int getDistance() {
28 return distance;
29 }
30
31 public float getDuration() {
32 return duration;
33 }
34 }
Chapter 10: Spring 309
Reactive controller
The controller provides the REST-endpoint which can be called from a client.
1 @RestController
2 @RequestMapping("/api")
3 public class DistanceController {
4
5 private final DistanceService distanceService;
6
7 public DistanceController(DistanceService distanceService) {
8 this.distanceService = distanceService;
9 }
10
11 @GetMapping(
12 value = "/distance",
13 produces = MediaType.APPLICATION_STREAM_JSON_VALUE
14 )
15 public Flux<DistanceMeasurement> distance() {
16 return this.distanceService.getDistances();
17 }
18 }
The magic happens in the service where the “Flux” is generated and gets new data on each interval.
Most of the code has already been explained in the Pi4J chapter. The pins are initialized in the
constructor and are used to do a measurement every second.
1 @Service
2 public class DistanceService {
3 private static final Logger logger = LoggerFactory
4 .getLogger(DistanceService.class);
5
6 private static final Pin PIN_TRIGGER = RaspiPin.GPIO_01; // BCM 18
7 private static final Pin PIN_ECHO = RaspiPin.GPIO_05; // BCM 24
8
9 private final GpioPinDigitalOutput trigger;
10 private final GpioPinDigitalInput echo;
11
12 public DistanceService() {
13 // Initialize the GPIO controller
14 GpioController gpio = GpioFactory.getInstance();
Chapter 10: Spring 310
15
16 // Initialize the pins
17 this.trigger = gpio
18 .provisionDigitalOutputPin(PIN_TRIGGER, "Trigger", PinState.LOW);
19 this.echo = gpio
20 .provisionDigitalInputPin(PIN_ECHO, "Echo", PinPullResistance.PULL_UP);
21 }
22
23 public Flux<DistanceMeasurement> getDistances() {
24 return Flux
25 .fromStream(Stream.generate(() -> this.getDistanceMeasurement()))
26 .delayElements(Duration.ofSeconds(1));
27 }
28
29 private DistanceMeasurement getDistanceMeasurement() {
30 try {
31 // Set trigger high for 0.01ms
32 this.trigger.pulse(10, PinState.HIGH, true, TimeUnit.NANOSECONDS);
33
34 // Start the measurement
35 while (this.echo.isLow()) {
36 // Wait until the echo pin is high,
37 // indicating the ultrasound was sent
38 }
39 long start = System.nanoTime();
40
41 // Wait till measurement is finished
42 while (this.echo.isHigh()) {
43 // Wait until the echo pin is low,
44 // indicating the ultrasound was received back
45 }
46 long end = System.nanoTime();
47
48 // Output the distance
49 float measuredSeconds = (end - start) / 1000000000F;
50 int distance = Math.round(measuredSeconds * 34300 / 2);
51
52 logger.info("Measured distance is: {} for {}s",
53 distance, measuredSeconds);
54
55 return new DistanceMeasurement(distance, measuredSeconds);
56 } catch (Exception ex) {
57 logger.error("Error: {}", ex.getMessage());
Chapter 10: Spring 311
58 }
59
60 return null;
61 }
62 }
Browser output when calling the api service on the Pi (in my case on IP 192.169.0.223):
Chapter 10: Spring 312
Conclusion
If we want to get data from a Pi sensor we can use reactive APIs and use the generated data on any
other device which can handle and parse this streamed data.
Just a thought: Impostor Syndrome
I have a confession to make. I’m suffering from a chronic disease, one which seems to be incurable,
the Impostor Syndrome. Every day I’m afraid of being exposed as a fraud, charlatan, hoax…
People with the Impostor Syndrome are convinced their achievements are based on luck instead
of knowledge or experience. They also believe other people think they are smarter than they are and
will realize this sooner or later.
Mosquitto will create the topic (= “mailbox”) as soon as one party wants to listen to it or publishes a
message in it, so they don’t need to be configured in advance. Any application or device (or multiple
ones) can publish a message to a topic.
Publish a message
Mosquitto will check who is subscribed to the topic and forward the message to all subscribed
applications.
Chapter 11: Message Queues 315
This way we achieve full “loose coupling”, which means both the publishers and subscribers don’t
need to know of the existence of each other. They only need to agree on the topic name and the
content of the messages they exchange via the queue.
Some example use-cases:
As you can imagine based on these examples the drawing can become a bit more complicated as
applications can be publisher, subscriber or both.
Installation
To install the broker (= the Mosquitto application) we need to do three steps:
1 $ mosquitto -v
2 1569780732: mosquitto version 1.5.7 starting
3 1569780732: Using default config.
4 1569780732: Opening ipv4 listen socket on port 1883.
5 1569780732: Error: Address already in use
1 $ netstat --listen
2 Active Internet connections (only servers)
3 Proto Recv-Q Send-Q Local Address Foreign Address State
4 tcp 0 0 0.0.0.0:1883 0.0.0.0:* LISTEN
5 tcp6 0 0 [::]:1883 [::]:* LISTEN
Later we will need to know where other devices need to connect to. So we need the network IP
address of the Pi on which we installed Mosquitto. We can check this with the following command:
1 $ hostname -I
2 192.168.0.213 2a02:1811:bc04:4900:412e:b96a:d93c:b0a2 2a02:1811:bc04:4900:11fb:315f:\
3 b8e1:f5dc
1 $ ifconfig
2 eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
3 ether dc:a6:32:21:c1:12 txqueuelen 1000 (Ethernet)
4 RX packets 0 bytes 0 (0.0 B)
5 RX errors 0 dropped 0 overruns 0 frame 0
6 TX packets 0 bytes 0 (0.0 B)
7 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
8
9 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
10 inet 127.0.0.1 netmask 255.0.0.0
11 inet6 ::1 prefixlen 128 scopeid 0x10<host>
12 loop txqueuelen 1000 (Local Loopback)
13 RX packets 0 bytes 0 (0.0 B)
14 RX errors 0 dropped 0 overruns 0 frame 0
15 TX packets 0 bytes 0 (0.0 B)
16 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
17
18 wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
19 inet 192.168.0.213 netmask 255.255.255.0 broadcast 192.168.0.255
20 inet6 2a02:1811:bc04:4900:11fb:315f:b8e1:f5dc prefixlen 64 scopeid 0x0<glo\
21 bal>
22 inet6 2a02:1811:bc04:4900:412e:b96a:d93c:b0a2 prefixlen 128 scopeid 0x0<gl\
23 obal>
24 inet6 fe80::1f70:9d7c:a379:f0f3 prefixlen 64 scopeid 0x20<link>
25 ether dc:a6:32:21:c1:13 txqueuelen 1000 (Ethernet)
26 RX packets 59629 bytes 74393867 (70.9 MiB)
27 RX errors 0 dropped 0 overruns 0 frame 0
28 TX packets 28575 bytes 3084130 (2.9 MiB)
29 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
1 $ mosquitto_sub -v -t 'testing/TestTopic'
In the second terminal we send multiple commands with a message for this topic, like this:
Chapter 11: Message Queues 318
Every “publish” from the second terminal window will appear in the first one.
Publishing to and subscribing from Mosquitto from Pi and PC at the same time
1 <artifactId>javafx-mosquitto</artifactId>
2
3 ...
4
5 <dependency>
6 <groupId>org.eclipse.paho</groupId>
7 <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
8 <version>1.2.2</version>
9 </dependency>
1 module be.webtechie {
2 requires javafx.controls;
3 requires org.eclipse.paho.client.mqttv3;
4 exports be.webtechie.javafxmosquitto;
5 }
Once the client is connected, we can send a message (“Hello from PC”) to the topic (= mailbox, e.g.
“testing/TestTopic”) with this code:
The full code with error handling is available in the sources in “QueueClient.java”.
Subscribing to Mosquitto
Subscribing to a topic is also done in the QueueClient script like this:
We use an ObservableList so we can use this in the UI later to show the incoming messages.
As you see it uses another class ClientCallback which implements MqttCallback, that will get
called each time a new message is published in “testing/TestTopic” and pushed to the subscribed
applications:
Chapter 11: Message Queues 321
We need to use Platform.runLater to avoid Thread errors between the Java app running the
connection, and the JavaFX thread which updates the screen.
Screenshot UI on PC
When we send a message to the queue, we also receive it back into the list as this application is both
publisher and subscriber to the same topic in Mosquitto.
Screenshot UI on Pi
On the Pi we see the same messages appearing and we can also push messages to the topic which
appear simultaneously on the PC!
Chapter 11: Message Queues 323
As you can see, this will be a more complex project using a lot of the knowledge we collected in the
previous chapters. It includes:
So we can send two different colors in the command, but some effects don’t use colors at all, or only
one and some don’t need the speed value. This is an overview of the available commands:
Some examples
We will also need extra libraries to be added to the Arduino IDE. In the “Tools” menu, select “Manage
libraries…” and search for these and click “Install”:
¹²²https://github.com/adafruit/Adafruit_NeoPixel
¹²³https://github.com/arduino-libraries/WiFiNINA
¹²⁴https://github.com/arduino-libraries/ArduinoMqttClient
Chapter 11: Message Queues 326
Scheme with Arduino Uno WiFi REV3, led strip and power supply
The test setup for this example uses an Arduino Uno WiFi REV2. This can be a bit confusing as
there are multiple Uno-types in the Arduino IDE from which you can select. Make sure to select the
correct one!
To make the code of the Arduino easy to understand, the functions are split up in different “ino”-files
with “WifiMosquittoListener.ino” being the main one:
Chapter 11: Message Queues 327
• WifiMosquittoListener.ino
* Main file with the setup and loop function
• ConnectionHandler
* Handler for incoming Mosquitto messages
• LedEffects
* Code to generate the different LED animations
• MessageHandler
* Converts the command which can be received from Mosquitto and Serial (for testing) into
values which are used by LedEffects
• SerialFunctions
* Function to check if serial data (with test command) is available
Take a look at these different files, some of them are further described here.
• setup()
* Is called once when the board starts or resets.
* Is used to initialize libraries, variables, pins…
• loop()
* Loops continuously to actively control the board.
Let’s take a look at how these two are used in our project. The actual code you find in the GitHub
sources contains even more Serial debug info. At the end of the setup, we already provide a message
so the LED strip starts with effect 2 (static fade).
Chapter 11: Message Queues 328
1 void setup() {
2 // Configure serial speed and wait till it is available
3 // This is used to output logging info and can receive LED commands
4 Serial.begin(9600);
5 while (!Serial) {
6 ; // wait for serial port to connect. Needed for native USB port only
7 }
8
9 // Initialize the leds
10 initLeds();
11
12 // Connecting to WiFi
13 Serial.println("--- Connecting to WiFi ---");
14 while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
15 // failed, retry
16 Serial.print(".");
17 delay(5000);
18 }
19
20 // Connecting to Mosquitto
21 Serial.println("--- Connecting to Mosquitto ---");
22 mqttClient.onMessage(onMqttMessage);
23 if (!mqttClient.connect(broker, port)) {
24 Serial.print("MQTT connection failed! Error code = ");
25 Serial.println(mqttClient.connectError());
26 } else {
27 mqttClient.subscribe(topic);
28 Serial.println("MQTT connection ready");
29 }
30
31 // Set the initial LED effect
32 String message = "2:0:14:255:0:255:5:0";
33 message.toCharArray(input, 50);
34 }
Once everything is configured and ready to use, the loop function will continuously check if new
messages are available in Mosquitto or Serial, convert the message to variables and call the correct
LED function.
Chapter 11: Message Queues 329
1 void loop() {
2 mqttClient.poll();
3 checkSerial();
4 handleMessage();
5
6 currentLoop++;
7
8 // Only do LED effect when loop exceeds the defined animationSpeed
9 if (currentLoop >= animationSpeed) {
10 // Depending on the commandId, call the correct LED effect
11 if (commandId == 1) {
12 setStaticColor();
13 } else if (commandId == 2) {
14 setStaticFade();
15 } else if (commandId == 3) {
16 setBlinking();
17 } else if (commandId == 4) {
18 // ... call the correct function for each commandId
19 }
20
21 currentLoop = 0;
22 }
23
24 delay(5);
25 }
The incoming (string) message in Arduino needs to be parsed to numeric values. So this will for
instance parse “2:25:255:0:0:0:0:250” to
• command id = 2
• speed = 25
• rgb1 = 0xFF0000
• rgb2 = 0x0000FF
This is done in MessageHandler.ino and the “magic” is in splitting the input on “:” and assign each
part to a value:
Chapter 11: Message Queues 330
1 void handleMessage() {
2 char* part = strtok(input, ":");
3 int position = 0;
4
5 while (part != 0) {
6 int value = atoi(part);
7
8 if (position == 0) {
9 commandId = value;
10 } else if (position == 1) {
11 animationSpeed = value;
12 } else if (position == 2) {
13 r1 = value;
14 } else if (position == 3) {
15 // ... handle each part and assign to a value
16 }
17
18 position++;
19 }
20 }
Mosquitto messages are received with a callback function which was configured in “setup()” -
mqttClient.onMessage(onMqttMessage); - and we put the received message in the “input” variable
which is later processed to values:
For easy testing, we can also send the same commands via “Tools” > “Serial Monitor”. And as you
can see in the screenshot, for the LED effects which don’t use speed or colors, we don’t need to send
the full string. E.g. “6” starts the static rainbow.
Chapter 11: Message Queues 331
Send LED command via the serial interface of the Arduino IDE
1 void checkSerial() {
2 if (Serial.available() > 0) {
3 String message = Serial.readString();
4
5 message.toCharArray(input, 50);
6 input[50] = 0;
7 }
8 }
In both functions, we make sure the last byte is 0. This is used later to make sure we don’t end up
in an endless loop where the input is handled.
LED effects
Only your imagination and programming skills are the limiting factor on what you can achieve…
;-) In “LedEffects.ino” the functions are included for the effects defined in the table before, but feel
free to go crazy and extend these!
Just some examples. First, the LED strip must be initialized, this function is called from “main” >
“setup()”:
Chapter 11: Message Queues 332
1 void initLeds() {
2 strip.begin();
3 strip.setBrightness(100);
4 strip.clear();
5 strip.show(); // Initialize all pixels to 'off'
6 }
For a running LED, we need to put one LED on color 2 and show it. The value for this LED is then
immediately put back to color 1, without showing it. That’s what we do the next time the same
function is called, and the next LED is put to color 2.
1 void setRunningLight() {
2 if (currentAction >= NUMBER_OF_LEDS) {
3 currentAction = 0;
4 }
5
6 // Show color 1
7 strip.setPixelColor(currentAction, rgb1);
8 strip.show();
9
10 // Reset to color 2 for next loop
11 strip.setPixelColor(currentAction, rgb2);
12
13 currentAction++;
14 }
There are also two helper functions to calculate the gradient color and a rainbow color:
Chapter 11: Message Queues 333
1 // Calculate a gradient color between color 1 and 2, for the given position
2 uint32_t getGradientColor(uint16_t pos) {
3 ...
4 }
5
6 // Pos from 0 to 255 to get colors from full-color wheel
7 // 0 - 85: G - R
8 // 85 - 170: R - B
9 // 170 - 255: B - G
10 uint32_t getWheelColor(byte pos) {
11 ...
12 }
• Undertow
* Webserver in code, so no extra installation needed
* Easy to add custom web functions
• JavaFX
* Make a UI to select the color and animation
* Visualize the active colors and animation on the Arduino
LED controller UI
EventManager
Within the application, we add an EventManager. This will allow us to have two different UI-parts
who listen to the incoming LED-commands.
18 *
19 * @param ledCommand {@link LedCommand}
20 */
21 public void sendEvent(LedCommand ledCommand) {
22 this.eventListeners.forEach(l -> l.onQueueMessage(ledCommand));
23 }
24 }
Mosquitto connection
We reuse the code from the first example in this chapter. But instead of an ObservableList to store
the incoming messages, we will use the EventManager to forward the message to the different
components of the application which were added to the list of listeners. This is done when the
LED panel is initialized:
This UI will change the color wheels and speed values according to the received command. And of
course, changing the color and pressing a button will send a command to Mosquitto so it will be
received by the Arduino. It is build up with a set of JavaFX components with some additional CSS
styling. This is the styling used for the LED-effect selection buttons:
Chapter 11: Message Queues 336
1 .ledButton {
2 -fx-font: 20px "Sans";
3 -fx-padding: 10;
4 -fx-background-color: #041E37;
5 -fx-text-fill: #728CA6;
6 -fx-font-weight: bold;
7 -fx-min-width: 200;
8 -fx-min-height: 30;
9 }
10
11 .ledButton:hover {
12 -fx-text-fill: yellow;
13 }
14
15 .ledButton:selected {
16 -fx-text-fill: #041E37;
17 -fx-background-color: yellow, #728CA6;
18 -fx-background-insets: 0 0 0 0, 2 2 2 2;
19 }
As you can see in “.ledButton:selected”, JavaFX styling allows you to use multiple colors for the
background. By adding different insets you can create borders and shadows.
LED controller UI
By changing this one CSS styling you can have even more combined colors in the background:
1 .ledButton:selected {
2 -fx-text-fill: #041E37;
3 -fx-background-color: white, yellow, red;
4 -fx-background-insets: 0 -6 -6 0, 0 0 0 0, 2 -2 -2 2;
5 }
LED controller UI
The color selection wheels are made by Gerrit Grunwald (see “Chapter 7: JavaFX”). As we want
this component to act when a new message is received from Mosquitto, it needs to implement
“EventListener”:
Chapter 11: Message Queues 337
An extract of the code for this UI below. The buttons and speed sliders are put in GridPane for a
nice structure.
37 GridPane.setHalignment(lblSpeed, HPos.CENTER);
38 effectButtons.add(lblSpeed, 0, 5, 2, 1);
39
40 this.slider = new Slider();
41 this.slider.setShowTickLabels(true);
42 this.slider.setShowTickMarks(true);
43 this.slider.valueProperty().addListener((o, old, new) -> this.sendMessage());
44 effectButtons.add(this.slider, 0, 6, 2, 1);
45
46 this.setEffect(LedEffect.ALL_OUT);
47 }
When a message is received from Mosquitto (via the onQueueMessage from the EventListener
interface), the color wheels and slider are changed:
1 /**
2 * {@link LedCommand} received from Mosquitto.
3 * We block sending updates back to Mosquitto until the interface is updated fully
4 * to match the received command, to avoid infinite loops.
5 */
6 @Override
7 public void onQueueMessage(LedCommand ledCommand) {
8 this.blockSending = true;
9
10 this.setEffect(ledCommand.getLedEffect());
11 this.slider.setValue(ledCommand.getSpeed());
12 this.colorSelector1.setSelectedColor(ledCommand.getColor1());
13 this.colorSelector2.setSelectedColor(ledCommand.getColor2());
14
15 this.blockSending = false;
16 }
Depending on the selected LedEffect the color wheels are enabled or disabled, on the slider values
updated:
Chapter 11: Message Queues 339
1 /**
2 * Handle the chosen effect from a button or a Mosquitto message
3 * to enable/disable the available UI elements and
4 * highlight the button of the selected {@link LedEffect}.
5 */
6 private void setEffect(LedEffect ledEffect) {
7 this.selectedLedEffect = ledEffect;
8
9 this.colorSelector1.setDisable(!ledEffect.useColor1());
10 this.colorSelector2.setDisable(!ledEffect.useColor2());
11 this.slider.setDisable(!ledEffect.useSpeed());
12 this.slider.setMin(ledEffect.getMinimumSpeed());
13 this.slider.setMax(ledEffect.getMaximumSpeed());
14
15 this.btStatic.setSelected(ledEffect == LedEffect.STATIC);
16 this.btStaticFade.setSelected(ledEffect == LedEffect.STATIC_FADE);
17 this.btBlinking.setSelected(ledEffect == LedEffect.BLINKING);
18 this.btRunning.setSelected(ledEffect == LedEffect.RUNNING);
19 this.btStaticRainbow.setSelected(ledEffect == LedEffect.STATIC_RAINBOW);
20 this.btFadingRainbow.setSelected(ledEffect == LedEffect.FADING_RAINBOW);
21 this.btWhite.setSelected(ledEffect == LedEffect.ALL_WHITE);
22 this.btClear.setSelected(ledEffect == LedEffect.ALL_OUT);
23
24 this.sendMessage();
25 }
1 /**
2 * Send a message to Mosquitto if a new effect and/or different parameters
3 * are selected.
4 */
5 private void sendMessage() {
6 if (this.blockSending) {
7 // Avoid sending the same command to Mosquitto again
8 // it to avoid infinite loops.
9 return;
10 }
11
12 LedCommand ledCommand = new LedCommand(
13 this.selectedLedEffect,
14 (int) this.slider.getValue(),
15 this.colorSelector1.getSelectedColor(),
Chapter 11: Message Queues 340
16 this.colorSelector2.getSelectedColor()
17 );
18
19 if (this.queueClient != null) {
20 this.queueClient.sendMessage(ledCommand);
21 }
22 }
Queue log UI
Queue log UI
This class also implements the EventListener interface and can store all the received messages in an
ObservableList
14 }
15 }
ReceivedMessage is a just a data class which holds a timestamp and the LedCommand:
1 /**
2 * Helper class to add a {@link LedCommand} to a table with a timestamp.
3 */
4 public class ReceivedMessage {
5 private final String timestamp;
6 private final LedCommand ledCommand;
7
8 private final DateTimeFormatter dateFormat =
9 DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
10
11 public ReceivedMessage(LedCommand ledCommand) {
12 this.timestamp = LocalDateTime.now().format(dateFormat);
13 this.ledCommand = ledCommand;
14 }
15
16 public String getTimestamp() {
17 return timestamp;
18 }
19
20 public LedCommand getLedCommand() {
21 return ledCommand;
22 }
23 }
The table is initialized within the class constructor. Each column has its own “setCellFactory”, which
can, for instance, change the background color of the cell to match the color of the LedCommand
value.
1 public QueueMessagesList() {
2 TableColumn colTimestamp = new TableColumn("Timestamp");
3 colTimestamp.setStyle("-fx-alignment: TOP-LEFT;");
4 colTimestamp.setMinWidth(150);
5 colTimestamp.setCellValueFactory(new PropertyValueFactory<>("timestamp"));
6
7 TableColumn colCommand = new TableColumn("Command");
8 colCommand.setStyle("-fx-alignment: TOP-LEFT;");
9 colCommand.setMinWidth(100);
Chapter 11: Message Queues 342
10 colCommand.setCellValueFactory(new PropertyValueFactory<>("ledCommand"));
11 colCommand.setCellFactory(column -> new TableCell<LedCommand, LedCommand>() {
12 @Override
13 protected void updateItem(LedCommand item, boolean empty) {
14 super.updateItem(item, empty);
15
16 if (item == null || empty) {
17 setText(null);
18 setStyle("");
19 } else {
20 setText(item.getLedEffect().name());
21 }
22 }
23 });
24
25 ...
26
27 TableColumn colColor1 = new TableColumn("Color 1");
28 colColor1.setStyle("-fx-alignment: TOP-CENTER;");
29 colColor1.setMinWidth(70);
30 colColor1.setCellValueFactory(new PropertyValueFactory<>("ledCommand"));
31 colColor1.setCellFactory(column -> new TableCell<LedCommand, LedCommand>() {
32 @Override
33 protected void updateItem(LedCommand item, boolean empty) {
34 super.updateItem(item, empty);
35
36 if (item == null || empty) {
37 setText(null);
38 setStyle("");
39 } else {
40 setText(item.getColor1().toString());
41 setStyle("-fx-background-color: " + item.getColor1().toString()
42 .replace("0x", "#"));
43 }
44 }
45 });
46
47 ...
48
49 this.getColumns().addAll(
50 colTimestamp,
51 colCommand,
52 colSpeed,
Chapter 11: Message Queues 343
53 colColor1,
54 colColor2);
55
56 this.setItems(this.queueItems);
57 }
To be able to change the LED strip from any PC within the same network as the Pi, we want to use
a webpage.
To achieve this, we need to add Undertow¹²⁵. This is a light-weight but very flexible Java-webserver
that you can fully integrate into an application. So let’s add it as a dependency in our pom.xml file:
1 <dependency>
2 <groupId>io.undertow</groupId>
3 <artifactId>undertow-core</artifactId>
4 <version>2.0.26.FINAL</version>
5 </dependency>
6 <dependency>
7 <groupId>io.undertow</groupId>
8 <artifactId>undertow-servlet</artifactId>
9 <version>2.0.26.FINAL</version>
10 </dependency>
¹²⁵http://undertow.io/
Chapter 11: Message Queues 344
And the handler is something we need to implement as a class that will return a webpage, a REST-
handler or whatever we want to provide. In this case, we are using a webpage where you select a
few predefined LED commands. The code is very simple as we only provide three options and some
checks. So you get the minimal idea but can extend as much as you want…
76 exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, sb.toString()
77 .length());
78 exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html");
79 Sender sender = exchange.getResponseSender();
80 exchange.setStatusCode(statusCode);
81 sender.send(sb.toString());
82 }
83 }
JavaFX on PC, terminal on Pi with Mosquitto and Arduino with LED strip
After this, log-off or restart the Pi and now you can start Wireshark, select your cable or WiFi
connection and watch the messages being transmitted over the network.
In the sources, you can find a Wireshark trace file with the communication between my Pi
and Arduino test setup.
Chapter_11_Queues > wireshark-traces > pi-receives-mosquitto-arduino-client.pcapng
With the filter “ip.addr == 192.168.0.213” we only get the messages to and from the Arduino in my
test setup. In packet 13 you can see an LED-command message which was successfully sent from
Pi (192.168.0.213) to Arduino (192.168.0.128). In the details of the packet (middle window) and the
bytes overview (bottom window) you can find back the full command “4:2:255:22:0:0:1:255”.
So at this moment, we are sure the commands are exchanged between Pi and Arduino.
Conclusion
Wow, what a journey… What started as some blog posts and a 4-page article for MagPi, turned into
this book!
Building the examples and understanding what needed to be done on the hardware level has been
pretty challenging sometimes. But in the end, all the examples I had in mind when starting this book
and creating the first draft of the table of contents, are here. Especially thanks to all those people
who volunteered to review and give feedback. I’m also honored the experts I admire, were willing
to spend some of their precious time for an interview!
Do I still think Java on Raspberry Pi is a good idea? You bet!!! More than ever, I learned Java is
the tool I love to create stuff, experiment and build. Is it the one-and-only-tool-for-everything? Of
course not! As always you have to choose wisely but I hope you can find enough approaches in this
book to combine the power of Java with the tools you love and know…
JavaFX is a no-brainer when you need a tool to create user interfaces and you can create visually
appealing screens with very little effort. But Arduino is the best fit to control, for example, LED-
strips. The GPIOs are wonderful to attach any kind of hardware and easy to control as shown in
“Chapter 9: Pi4J”, but sometimes it’s easier to find an example Python script for more complex
components. But you can start these scripts from Java with parameters as described in “Chapter 8:
Bits and Bytes”.
As with any good software project you have to select the tools that fit your needs in the best
possible way. And most of the times it will be a combination of different things. But anyhow there
is a big chance the Raspberry Pi will be the centerpiece of it. This small and cheap computer has
proven once more it’s a “game-changer”!
Now let me answer the question I asked all interviewees in this book…
Which DIY-programming-electronics-project are you working on, or is on your “if I ever have time”
list?
The project I had in mind when starting my Java-on-Raspberry-Pi-experiments is a combination of
some of the examples in this book. For my son, I’ve built a drum booth some time ago so he can
continue his love for playing music without all the noise for my wife and myself. In that booth, I
want to add a touch-screen with a user interface to control LED-strips on the ceiling attached to an
Arduino, different types of lights with a relay-board on the Pi, a web-interface for us so that we can
alarm him the food is on the table by turning those LED-strips into flashing red alarm signal… For
this project, different examples from this book must be combined.
So one final note to you and myself: hop hop get to work, build, experiment and most
importantly… have fun!!!