Is it winter or not rather fall right now ? We do not know for sure right now . Weather is always an important topic for conversation. So we are going to be a professional weatherman – with Java, JavaFX and Tinkerforge.
To be able to make a statement about the weather we do not need a poor frog that is confined in a glass and climbs up and down a ladder every once in a while. We can also build a frog-friendly weather station.
The components
==============
For our weather station we need the following ingredients today: a temperature-, a light- and a barometer sensor. This way we are able to measure the air pressure, the barometric height and the luminosity (in Lux).
The temperature-(Link) and barometer sensor(Link) was already part of the previous articles. New for us today is the light sensor. Additionally we are using an 20×4-LCD-display.
The Light Sensor
========================
The light sensor (Ambient Light Sensor) is able to measure the brightness of the environment and provides the value in Lux. The resolution (0 Lux-900 Lux) is 0,1 which equals 12 bit. With approximately 2 g the light sensor is one of the lightest and uses only 1 mAt.
The Weatherstation
==================
As always (see previous articles) all elements are plugged into the master and shortly after they appear on the display of the BrickViewer. Note: Do not forget to update your sensor software if a newer version is available.
All sensors can be used with the Java-Interface which provides the usual ActionListener concept. Additionally every sensor can be requested directly. But keep in mind that this method leads to an unnecessary high bandwidth. The sensorsin this example are programmed without JavaFX because this time no visualization with LineChart is shown. As an example in listing 1: the barometer. Instead of the JavaFX-Elements this time we write directly into the 20×4-LCD display. So far nothing special.
1public class Light implements Runnable {
2
3 private String UID;
4 private int callbackPeriod;
5 private LCD20x4 lcd20x4 = new LCD20x4("jvX");
6
7 public Light(final String UID, int callbackPeriod) {
8 this.UID = UID;
9 this.callbackPeriod = callbackPeriod;
10 }
11
12 @Override
13 public void run() {
14 IPConnection ipcon = new IPConnection();
15 BrickletAmbientLight bricklet
16 = new BrickletAmbientLight(UID, ipcon);
17 try {
18 ipcon.connect(Localhost.HOST, Localhost.PORT);
19
20 bricklet.setIlluminanceCallbackPeriod(callbackPeriod);
21 bricklet.addIlluminanceListener(illuminance -> {
22 final double lux = illuminance / 10.0;
23 final String text = "Lux : "
24 + lux + " Lux";
25 lcd20x4.printLine(3, text);
26 });
27 } catch (IOException
28 | AlreadyConnectedException
29 | TimeoutException | NotConnectedException e) {
30 e.printStackTrace();
31 }
32 }
33}
The 20×4-LDC-Bricklet
=========================
The LCD brick let contains 20×4 dot matrix inclusively a blue background lightning. Additionally there are four buttons at the lower edge of the board. The API enables us to directly write individual characters or whole rows up to a length of 20 characters. The background lightning can be switched on and off and also the state of the buttons can be read. With this LCD bricklet the data of the connected sensors are displayed. Every sensor value is assigned an own row. In our example the following rows are assigned as follows:
- Temperature in degree Celsius
- Air pressure in Millibar
- Barometric height in meters
- Luminosity in Lux
The advantage with the implementation of the 20×4-LCD display is that it is Thread-safe (italic). The brick let can be provided with data competitively by different threads without having to expect problems. The dispribution of the rows simplifies the programming a lot since only the particular sensor is responsible for the clear display of its own row. Since here for reasons of simplification per sensor unit only one instance of the LCD brick let is generated also the initialization is scrolled through multiple times. For our example this is sufficient for now.
In order to show the requested characters on the LCD-bricklet they first have to be converted in a bit pattern. For this purpose the method String utf16ToKS0066U(String utf16) (also contained in the exemplary source code) can be extracted from the TinkerForge documentation. After the coding the text of max. 20 characters per row can be displayed with the method writeLine() (Listing 2)
1public void printLine(short lineNr, final String text) {
2 try {
3 lcd.writeLine(lineNr, (short)0, clearLine);
4 lcd.writeLine(lineNr, (short)0, utf16ToKS0066U(text));
5 } catch (TimeoutException | NotConnectedException e) {
6 e.printStackTrace();
7 }
8}
Listing 3 shows the complete implementation of the class LCD20x4 (italic).
1public class LCD20x4 {
2
3 private BrickletLCD20x4 lcd;
4
5 public LCD20x4(final String UID) {
6 IPConnection ipcon = new IPConnection();
7 lcd = new BrickletLCD20x4(UID, ipcon);
8 try {
9 ipcon.connect(Localhost.HOST, Localhost.PORT);
10 lcd.backlightOn();
11 lcd.clearDisplay();
12 lcd.setDefaultTextCounter(-1);
13 } catch (IOException
14 | AlreadyConnectedException
15 | TimeoutException | NotConnectedException e) {
16 e.printStackTrace();
17 }
18 }
19
20
21 private final String clearLine
22 = utf16ToKS0066U(" ");
23
24
25 public void printLine(short lineNr, final String text) {
26 try {
27 lcd.writeLine(lineNr, (short)0, clearLine);
28 lcd.writeLine(lineNr, (short)0, utf16ToKS0066U(text));
29 } catch (TimeoutException | NotConnectedException e) {
30 e.printStackTrace();
31 }
32 }
33
34 public void printLine(int lineNr, final String text) {
35 printLine((short) lineNr, text);
36 }
37
38 static String utf16ToKS0066U(String utf16)
39 {
40 String ks0066u = "";
41 char c;
42
43 for (int i = 0; i < utf16.length(); i++) {
44 int codePoint = utf16.codePointAt(i);
45
46 if (Character.isHighSurrogate(utf16.charAt(i))) {
47 // Skip low surrogate
48 i++;
49 }
50
51 // ASCII subset from JIS X 0201
52 if (codePoint >= 0x0020 && codePoint <= 0x007e) {
53 // The LCD charset doesn't include '\'
54 // and '~', use similar characters instead
55 switch (codePoint) {
56 case 0x005c: c = (char)0xa4; break;
57 // REVERSE SOLIDUS maps to IDEOGRAPHIC COMMA
58 case 0x007e: c = (char)0x2d; break;
59 // TILDE maps to HYPHEN-MINUS
60 default: c = (char)codePoint; break;
61 }
62 }
63 // Katakana subset from JIS X 0201
64 else if (codePoint >= 0xff61
65 && codePoint <= 0xff9f) {
66 c = (char)(codePoint - 0xfec0);
67 }
68 // Special characters
69 else {
70 switch (codePoint) {
71 case 0x00a5: c = (char)0x5c; break;
72 // YEN SIGN
73 case 0x2192: c = (char)0x7e; break;
74 // RIGHTWARDS ARROW
75 case 0x2190: c = (char)0x7f; break;
76 // LEFTWARDS ARROW
77 case 0x00b0: c = (char)0xdf; break;
78 // DEGREE SIGN maps
79 // to KATAKANA SEMI-VOICED SOUND MARK
80 case 0x03b1: c = (char)0xe0; break;
81 // GREEK SMALL LETTER ALPHA
82 case 0x00c4: c = (char)0xe1; break;
83 // LATIN CAPITAL LETTER A WITH DIAERESIS
84 case 0x00e4: c = (char)0xe1; break;
85 // LATIN SMALL LETTER A WITH DIAERESIS
86 case 0x00df: c = (char)0xe2; break;
87 // LATIN SMALL LETTER SHARP S
88 case 0x03b5: c = (char)0xe3; break;
89 // GREEK SMALL LETTER EPSILON
90 case 0x00b5: c = (char)0xe4; break;
91 // MICRO SIGN
92 case 0x03bc: c = (char)0xe4; break;
93 // GREEK SMALL LETTER MU
94 case 0x03c2: c = (char)0xe5; break;
95 // GREEK SMALL LETTER FINAL SIGMA
96 case 0x03c1: c = (char)0xe6; break;
97 // GREEK SMALL LETTER RHO
98 case 0x221a: c = (char)0xe8; break;
99 // SQUARE ROOT
100 case 0x00b9: c = (char)0xe9; break;
101 // SUPERSCRIPT ONE maps to SUPERSCRIPT (minus) ONE
102 case 0x00a4: c = (char)0xeb; break;
103 // CURRENCY SIGN
104 case 0x00a2: c = (char)0xec; break;
105 // CENT SIGN
106 case 0x2c60: c = (char)0xed; break;
107 // LATIN CAPITAL LETTER L WITH DOUBLE BAR
108 case 0x00f1: c = (char)0xee; break;
109 // LATIN SMALL LETTER N WITH TILDE
110 case 0x00d6: c = (char)0xef; break;
111 // LATIN CAPITAL LETTER O WITH DIAERESIS
112 case 0x00f6: c = (char)0xef; break;
113 // LATIN SMALL LETTER O WITH DIAERESIS
114 case 0x03f4: c = (char)0xf2; break;
115 // GREEK CAPITAL THETA SYMBOL
116 case 0x221e: c = (char)0xf3; break;
117 // INFINITY
118 case 0x03a9: c = (char)0xf4; break;
119 // GREEK CAPITAL LETTER OMEGA
120 case 0x00dc: c = (char)0xf5; break;
121 // LATIN CAPITAL LETTER U WITH DIAERESIS
122 case 0x00fc: c = (char)0xf5; break;
123 // LATIN SMALL LETTER U WITH DIAERESIS
124 case 0x03a3: c = (char)0xf6; break;
125 // GREEK CAPITAL LETTER SIGMA
126 case 0x03c0: c = (char)0xf7; break;
127 // GREEK SMALL LETTER PI
128 case 0x0304: c = (char)0xf8; break;
129 // COMBINING MACRON
130 case 0x00f7: c = (char)0xfd; break;
131 // DIVISION SIGN
132
133 default:
134 case 0x25a0: c = (char)0xff; break; // BLACK SQUARE
135 }
136 }
137
138 // Special handling for 'x' followed by COMBINING MACRON
139 if (c == (char)0xf8) {
140 if (!ks0066u.endsWith("x")) {
141 c = (char)0xff; // BLACK SQUARE
142 }
143 if (ks0066u.length() > 0) {
144 ks0066u = ks0066u.substring(0, ks0066u.length() - 1);
145 }
146 }
147 ks0066u += c;
148 }
149 return ks0066u;
150 }
151}
The usage
——————————
The implementing happens in the main-method of the class WeatherStation (Listing 4). All sensors are started in a separate thread. In order for the program to not be terminated ahead of time we wait on the command line as long as the user types in an „O“ followed by ENTER.
1public class WeatherStation {
2
3 private static int callbackPeriod = 10000;
4
5 public static void main(String args[]) throws Exception {
6 new Thread(
7 new Temperature("dXj", callbackPeriod)).start();
8 new Thread(new Barometer("jY4", callbackPeriod)).start();
9 new Thread(new Light("jy2", callbackPeriod)).start();
10
11 final BufferedReader in
12 = new BufferedReader(new InputStreamReader(System.in));
13
14 final Thread t = new Thread(() -> {
15 System.out
16 .println("press Q THEN ENTER to terminate");
17 int quit=0;
18 while(true){
19 try {
20 Thread.sleep(1000);
21 String msg = null;
22 while(true){
23 try{
24 msg=in.readLine();
25 }catch(Exception e){}
26 if(msg != null &&
27 msg.equals("Q")) { quit = 1; }
28 if(quit==1) break;
29 }
30 } catch (InterruptedException e) {
31 e.printStackTrace();
32 }
33 break;
34 }
35
36 });
37 t.start();
38 }
39}
Summary
————————
In this version the weather station is still connected to the computer via USB. In one of the next articles I am going to show how the weather station can be decoupled from the PC. It then will be possible to run the weather station e.g. outside in a dry place with power supply and still get the evaluation comfortably at the computer in JavaFX. For ideas, suggestions or questions please just contact me on Twitter: @SvenRuppert
Stay tuned. Happy coding!
The source code to this article can be found under
https://bitbucket.org/rapidpm/jaxenter.de-0012-iot-tinkerforge .
For people who are interested in more complex examples I recommend the following
https://bitbucket.org/rapidpm/modules .
More articles
fromSven Ruppert
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Sven Ruppert
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.