IoT ist immer heiß! Temperaturmessung mit dem PTC-Bricklet

Internet of Things mit Java 8 und TinkerForge, Teil 4

Sven Ruppert
© S&S Media

Kaffee im Büro ist meist eine heimtückische Angelegenheit: Erst ist er zu heiß, dann zu kalt. Kaum einer, der das Problem nicht kennt. Wir werden es uns heute vorknöpfen und eine Lösung im Ansatz skizzieren. Wie immer mit dabei: JavaFX und das PTC-Bricklet von TinkerForge.

Software wird aus Kaffee gemacht. Oder so ähnlich höre ich es immer wieder. Umso ärgerlicher, dass Kaffee nie die richtige Temperatur hat. Das nervt, mich zumindest gewaltig. Zu Beginn ist er zu heiß, also lässt man die Tasse stehen und widmet sich wieder seiner Aufgabe. Irgendwann denkt man wieder an den Kaffee, nimmt einen Schluck – und er ist zu kalt. Das muss nicht sein.

Das PTC-Bricklet

Das PTC-Bricklet aus dem TinkerForge-Baukasten misst Temperaturen mittels eines Pt100- und Pt1000-Elements. Dabei werden 2-, 3- und 4-Leitertypen unterstützt, was für eine hohe Flexibilität sorgt. Das Bricklet misst Temperaturen mit einer Genauigkeit von 0,5 % im Bereich von -246 bis 849 Grad Celsius. Dabei werden die Werte mit 15 Bit kodiert, was einer Auflösung von 0,03125°C entspricht, die wiederum in 0,01-Grad-Schritten ausgegeben werden. Damit sollte die Auflösung den meisten Anforderungen genügen. Ich verwende heute in unserem Aufbau einen PTC100. Welchen Sie verwenden ist nicht ausschlaggebend. Eine wasserfeste Version sollte es allerdings sein, sonst könnte es zu Überraschungen kommen.

Verwendung des PTC

Wie gehabt (siehe vorhergehende Artikel) wird das Bricklet an den Master angeschlossen. Kurz darauf erscheint der Sensor in der Anzeige des BrickViewers. Es ist immer ratsam, mittels BrickViever ein Update der Bricklet-Software durchzuführen. Damit ist der Sensor nun einsatzbereit. Das PTC Bricklet ist auch mit einer Java-Schnittstelle ausgestattet, die eine Programmierung mittels ActionListener (Listing 1) ermöglicht.

public class PTC implements Runnable {

    private String UID;
    private ObservableList seriesData;
    private SevenSegment sevenSegment = new SevenSegment("iW3");

    public PTC(final String UID, final XYChart.Series series) {
        this.UID = UID;
        this.seriesData = series.getData();
    }

    @Override
    public void run() {
        IPConnection ipcon = new IPConnection();
        BrickletPTC ptc = new BrickletPTC(UID, ipcon);
        try {
            ipcon.connect(Localhost.HOST, Localhost.PORT);
            ptc.setTemperatureCallbackPeriod(1000);
            ptc.addTemperatureListener(
              new BrickletPTC.TemperatureListener() {
                @Override
                public void temperature(int temperature) {
                    //schreibe temp in 7Seg
                    final double celcius = temperature / 100.0;
                    System.out.println("celcius = " + celcius);

                    Platform.runLater(()->{
                        final XYChart.Data data 
                            = new XYChart.Data(new Date(), celcius);
                        seriesData.add(data);
                    });
                    sevenSegment.printValue(celcius);

                }
            });
        } catch (IOException 
            | AlreadyConnectedException 
            | TimeoutException 
            | NotConnectedException e) {
            e.printStackTrace();
        }
    }
}

Innerhalb des ActionListeners werden einem die benötigten Werte übergeben. In unserem Fall ist es die Temperatur in Grad Celsius, multipliziert mit dem Faktor 100. Der gelieferte Wert selbst muss also durch 100 geteilt werden, damit er angezeigt werden kann.

Das 7-Segment-Bricklet

Was machen wir nun mit den gemessenen Werten? Zum einen stellen wir diese wie in den vorherigen Teilen auch in einem LineChart dar. Allerdings gibt es da auch noch das 7-Segment-Bricklet. Genau dieses werden wir uns heute ebenfalls ansehen. Mit diesem Bricklet stehen vier 7-Segment-Anzeigen zur Verfügung. Jedes der 29 Segmente kann eigenständig ein- und aus- als auch in der Helligkeit geschaltet werden. Die Kodierung der Segmente erfolgt über Bits bzw. Bit-Muster. Das macht es notwendig, die anzuzeigenden Werte vorher in das jeweilige Segmentmuster umzurechnen. In der Dokumentation von TinkerForge findet man die Bitmuster für die gängigsten Zeichen (auch im Beispielquelltext enthalten).

public class SevenSegment {

    private String UID;
    private BrickletSegmentDisplay4x7 sevenSegment;
    private DecimalFormat myFormatter = new DecimalFormat("0000");

    private static final byte[] digits = {0x3f,0x06,0x5b,0x4f,
            0x66,0x6d,0x7d,0x07,
            0x7f,0x6f,0x77,0x7c,
            0x39,0x5e,0x79,0x71}; // 0~9,A,b,C,d,E,F

    public SevenSegment(String UID) {
        this.UID = UID;
        final IPConnection ipcon = new IPConnection();
        sevenSegment = new BrickletSegmentDisplay4x7(UID, ipcon);
        try {
            ipcon.connect(Localhost.HOST, Localhost.PORT);

            short[] segments = {digits[4], 
                digits[2], digits[2], digits[3]};
            sevenSegment.setSegments(segments, (short)7, false);

        } catch (IOException 
            | AlreadyConnectedException 
            | NotConnectedException 
            | TimeoutException e) {
            e.printStackTrace();
        }
    }


    public void printValue(final Double value){
        int intValue = value.intValue();
        final char[] chars = myFormatter.format(intValue).toCharArray();
        System.out.println(chars);

        final int aChar = chars[0];
        final byte d1 = digits[aChar-48];
        final byte d2 = digits[chars[1]-48];
        final byte d3 = digits[chars[2]-48];
        final byte d4 = digits[chars[3]-48];
        short[] segments = {d1, d2, d3, d4};
        try {
            sevenSegment.setSegments(   segments   ,(short)7, false);
        } catch (TimeoutException 
                    | NotConnectedException e) {
            e.printStackTrace();
        }
    }

}


Die Umrechnung ist in unserem Fall recht einfach: Man nehme den gelieferten Wert aus dem PTC, teile diesen durch 100 und erzeuge das notwendige Bitmuster. In unserem Beispiel zeige ich auf der 7-Segment-Anzeige nur die Stellen vor dem Komma an, inklusive der führenden Nullen. Das Formatieren übernimmt für mich eine Instanz der Klasse DecimalFormat mit dem Pattern „0000“.

Die Stellen werden dann einzeln in das notwendige Bitmuster überführt. Zusammengefasst in einem short-Array werden die Bitmuster dann übergeben. Damit ist die Grundfunktion hergestellt. Immer dann, wenn der PTC einen Wert liefert, wird dieser umgerechnet und direkt an die 7-Segment – Anzeige übergeben. Damit kann nun die Temperatur dort abgelesen werden.

[ header = Der Einsatz ]

Der Einsatz

Nun sind alle Teile zusammen. Die Temperatur kann gemessen werden, der Wert wird angezeigt. Einmal in dem bekannten LineChart und ebenfalls auf der 7-Segment-Anzeige. Nun fehlt nur noch der Test am Kaffee selbst. Es ist also Zeit, sich frischen, heißen Kaffee zu holen. Starten Sie das Programm und befördern Sie den PTC in den Kaffeebecher. In diesem Beispiel muss die Temperatur noch selbst beobachtet werden. Das löst noch nicht das zu Beginn beschriebene Problem, ist aber der erste Schritt dorthin. Weitere Schritte folgen im nächsten Artikel.

In Listing 3 ist das vollständige JavaFX-Programm zu sehen.

public class PTCMaster extends Application {

    public static XYChart.Series seriesTemp = new XYChart.Series();

    public static void main(String args[]) throws Exception {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart TinkerForge Sample");

        final VBox box = new VBox();
        seriesTemp.setName("Temp");
        final ObservableList boxChildren = box.getChildren();
        boxChildren.add(createLineChart("Temp", seriesTemp));
        Scene scene = new Scene(box);

        stage.setScene(scene);
        stage.show();
        Platform.runLater(new PTC("i2J", seriesTemp));

    }

    private LineChart createLineChart(final String chartName,
        final XYChart.Series series ){
        final DateAxis dateAxis = new DateAxis();
        dateAxis.setLabel("Time");
        final NumberAxis yAxis = new NumberAxis();

        final LineChart lineChart 
            = new LineChart<>(dateAxis, yAxis);
        lineChart.setTitle(chartName);
        lineChart.getData().add(series);

        return lineChart;
    }

}

Fazit

Aus den Komponenten kann man innerhalb von Minuten einfache Dinge aufbauen und ausprobieren. Über die Sinnhaftigkeit genau dieser Anwendung kann natürlich diskutiert werden. Sicher ist auf jeden Fall, dass mit den TinkerForge-Elementen schnell Prototypen aufgebaut werden können. Dank der einfachen Java-Anbindung ist auch die Auswertung zügig in der ersten Version vorhanden. Wir werden in den nächsten Teilen nicht nur weitere Elemente kennenlernen, sondern auch komplexere Aufbauten erarbeiten. Stay tuned. Happy coding!

Die Quelltexte zu diesem Text sind unter [1] zu finden. Wer umfangreichere Beispiele zu diesem Thema sehen möchte, dem empfehle einen Blick auf [2]. Bei Ideen, Anregungen oder Fragen bin ich über Twitter (@SvenRuppert) oder E-Mail (sven.ruppert@gmail.com) zu erreichen.

Geschrieben von
Sven Ruppert
Sven Ruppert
Sven Ruppert arbeitet seit 1996 mit Java und ist Developer Advocate bei Vaadin. In seiner Freizeit spricht er auf internationalen und nationalen Konferenzen, schreibt für IT-Magazine und für Tech-Portale. Twitter: @SvenRuppert
Kommentare

Hinterlasse einen Kommentar

2 Kommentare auf "Internet of Things mit Java 8 und TinkerForge, Teil 4"

avatar
400
  Subscribe  
Benachrichtige mich zu:
tobi
Gast

Da ist ein Tippfehler im TemperatureListener.
Vermutlich sollte da sevenSegment.printValue(celcius); stehen…

Sven Ruppert
Gast

Hallo Tobi,
ja ist ein TippFehler im Namen.. Danke für den Hinweis.
Werden wir ändern..

Grüße
Sven