RaspberryPi – Temperatur messen und in einer Android Application anzeigen – Teil 3

So nach etwas längerer Pause kommt nun der letzte Teil dieser Serie. In diesem Teil solltet ihr bereits über ein Cronjob verfügen, welcher die Daten nach einem bestimmten Zeitpunkt in die Datenbank speichert (Teil 1), sowie ein TCP Server der uns entsprechend diese Daten über JSON Objekte bereitstellt (Teil 2). Im letzten Teil werden wir uns an die Programmierung der App kümmern. Fangen wir an!

Teil 1: Aufbau der Applikation

Ich werde hier den Aufbau präsentieren, den ich bei mir auf dem Handy umgesetzt habe. Schauen wir uns doch zuerst die Haupt-Activity an:Screenshot_2015-07-20-20-12-12Diese Ansicht wird beim Start der APP geöffnet. Hier sieht man die aktuell ausgelesene Temperatur. Je nach dem Wert ändert sich die Schriftfarbe und die Grafik links. Unten kann man sich den Temperaturverlauf anzeigen lassen oder die Statistik aufrufen. Der Temperaturverlauf sieht so aus:Screenshot_2015-07-20-20-12-37

 

Für dieses Beispiel habe ich alle drei Stunden die Temperatur gemessen. Die Y-Achse habe ich ausgeblendet. Die X-Achse startet um 0:00 Uhr und geht bis 21:00 Uhr. Unten sieht man noch für welchen Tag diese Skala gilt. Durch Wischbewegungen lässt sich der Verlauf Tag vor und zurück bewegen. Beim Doppelklick auf das Diagramm wird ein kleines Fenster ausgegeben:

Screenshot_2015-07-20-20-12-45Für die Statistik habe ich mir nicht besonders viel Mühe gegeben. Sie sieht eben sch..ße aus ;):

Screenshot_2015-07-20-20-12-59Teil 2: Die MPAndroidChart und die JSON Simple Bibliothek

Für die angezeigten Diagramme habe ich die MPAndroidChart Bibliothek benutzt. Ihr könnt sie euch hier herunterladen: Download. Die Bibliothek darf kostenlos benutzt werden aber über eine Spende würde sich der Autor definitiv freuen.Wie die Bibliothek in das Projekt eingebunden wird, muss ich glaube ich nicht erklären. Wenn doch, findest du die Erklärung in dem Tutorial zu der H2 Datenbank. Zusätzlich müssen wir auch die JSONSimple Bibliothek einbinden damit wir die Daten vom Server (RaspberryPi) verarbeiten können.

Teil 3: Programmieren

Sooooo… da ich die APP schon vor Wochen fertig hatte aber erst jetzt diesen Beitrag schreibe, werde ich mich durch den Code genauso durchkämpfen müssen wir ihr. Zumindest können wir erstmal ein neues Android Projekt (2.2 +) anlegen und die MPAndroidChart sowie die JSON Simple Bibliothek einbinden. Das Projekt bei mir besteht aus 5 Klassen wobei drei von den die Angezeigte Activity übernehmen, eine die TCP Verbindung und eine die Berechnung der Diagramm – Daten. Bei mir heißt das ganze Projekt „TempLooker“, die Klassen habe ich so genannt:

MainActivity  -> Zeigt die Hauptsicht an (Momentane Temperatur, die Grafik usw.)
ChartActivity -> Anzeigen der Temperatur im Diagramm
StatsActivity -> Anzeigen der Statisitk
TCPConnect    -> Verbindung zu der Datenbank herstellen
ChartData     -> Daten für das Diagramm vorbereiten

Ich werde jede Klasse durchgehen bis wir hoffentlich am Ende ein funktionierendes Programm haben.

3.1 MainActivity

Ich werde nicht die Activity selbst erklären. Am Ende könnt ihr euch dieses Projekt herunterladen, falls ihr wirklich den gleichen Aufbau haben wollt. Ich kann euch sagen welche Elemente die Activity braucht damit das Projekt funktioniert. Die Anordnung überlasse ich euch:

2 Buttons - ImageView - TextView

Und so sieht die MainActivity Klasse aus:

public class MainActivity extends Activity implements OnClickListener {
     private ImageView temp_icon;
     private TextView currenttemp;
     private Button showchart,stats;
     private JSONObject tempdata;
 
     private int icon_id,color_id;
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main_activity);
 
          temp_icon = (ImageView)findViewById(R.id.img_currenttemp);
          currenttemp = (TextView)findViewById(R.id.main_txt_currenttemp);
          showchart = (Button)findViewById(R.id.main_btn_showchart);
          stats = (Button)findViewById(R.id.main_btn_stats);
 
          UpdateData();
          showchart.setOnClickListener(this);
          stats.setOnClickListener(this);
      }
      @Override
      protected void onRestart(){
           super.onRestart();
           UpdateData();
      }
 
      private void UpdateData(){
           tempdata = _getJsonData();
           showTempIcon(Float.valueOf(tempdata.get("CURRENTTEMP").toString()));
 
           temp_icon.setBackgroundResource(icon_id);
           currenttemp.setText(tempdata.get("CURRENTTEMP").toString() + " \u2103");
           currenttemp.setTextColor(color_id);
      }
 
      private void showTempIcon(Float temp) {
           if (temp >= 28){
                icon_id = R.drawable.hot1;
                color_id = getResources().getColor(R.color.hot1);
           }
           if (temp < 28 && temp >= 21){
                icon_id = R.drawable.hot2;
                color_id = getResources().getColor(R.color.hot2);
           }
           if (temp < 21 && temp >= 16){
                icon_id = R.drawable.hot3;
                color_id = getResources().getColor(R.color.hot3);
           }
           if (temp < 16 && temp >= 10){
                icon_id = R.drawable.cold1;
                color_id = getResources().getColor(R.color.cold1);
           }
           if (temp < 10 && temp >= 3){
                icon_id = R.drawable.cold2;
                color_id = getResources().getColor(R.color.cold2);
           }
           if (temp < 3){
                icon_id = R.drawable.cold3;
                color_id = getResources().getColor(R.color.cold3);
           }
      }

      @SuppressWarnings("unchecked")
      private JSONObject getJsonData() {
           JSONObject tcpData = new JSONObject();
           tcpData.put("ID","TEMP");
           tcpData.put("COMMAND","CURRENTTEMP");
           JSONObject response = new JSONObject();
           try {
                response = new TCPConnect().execute(tcpData).get();
           } catch (InterruptedException e) {
                response.put("ERR",e.toString());
           } catch (ExecutionException e) {
                response.put("ERR",e.toString());
           }
           return response;
      }

      @Override
      public void onClick(View v) {
           if (v.getId() == R.id.main_btn_showchart){
                startActivity(new Intent(this,ChartActivity.class));
           }
           if (v.getId() == R.id.main_btn_stats){
                startActivity(new Intent(this,StatsActivity.class));
           }
      }
}

Zuerst brauchen wir die Objekte der Activity und zusätzlich ein JSON Objekt. Dazu kommen noch zwei Integer für die Grafik ID und richtige Farben ID. Danach folgt die onCreate Methode. Hier initialisieren wir alle Objekte von oben. Danach wird die Methode UpdateData() ausgeführt.Am Ende brauchen wir noch den Listener für die zwei Buttons. Dazu müssen wir die Klasse „OnClickListerner“ und die Methode „onClick“ in unsere Klasse implementieren. Aber das kennen wir schon von anderen Projekten. Die überschriebene Methode „onRestart“ wird jedesmal ausgeführt wenn die Activity angezeigt wird. Das brauchen wir falls wir zum Beispiel von der Activity „Statistiken“ zurück in die MainActivity wechseln und die Temperatur sich zu diesem Zeitpunkt geändert hat. So sind wir immer auf dem neusten Stand. Aber was macht die UpdateData() Methode genau? Zuerst werden in das JSON Objekt „tempdata“ die Daten von der Methode „getJsonData“ übergeben. Aber dazu später mehr. Danach rufen wir die Methode „showTempIcon“ auf die uns einmal die passende Ressource ID zu der Grafik (icon_id) und der Farbe (color_id) liefert. Haben wir die Daten nutzen wir sie um einmal die Grafik über „setBackgroundResource“ zu holen und sie im ImageView zu setzen. Danach folgt der Text (Temperaturwert) sowie die Schriftfarbe. Die Methode „showTempIcon“ erwartet den Temperaturwert als Float. Jetzt folgt eine einfache Abfrage des Wertes, wo je nachdem wie hoch oder niedrig dieser ausfällt entsprechende ID’s geholt werden. Die PNG’s habe ich kostenlos von flaticon heruntergeladen. Diese braucht ihr nur in eines der Drawable Ordner (je nach eurer Auflösung) zu kopieren. Die Farben lassen sich unter Values in einer .xml Datei speichern. Die zu überprüfenden Werte könnt ihr natürlich nach belieben verändern( wenn ihr zum Beispiel mehr Grafiken zur Auswahl habt). Die vorletzte Methode „getJSONData“ holt sich die momentane Temperatur vom Server ab. Dazu erstellen wir zuerst ein JSON Objekt „tcpData“ mit der ID „Temp“ und dem Kommando „CURRENTTEMP“. Für die Antwort vom Server erstellen wir noch das Objekt „response“. Danach folgt ein Aufruf über die TCPConnect Klasse wo im Endeffekt die Temperatur in das JSONObjekt „response“ gespeichert wird. Die letzte Methode onClick wird über den bereits angesprochenen Listener aufgerufen. Hier wird je nach gedrücktem Button die entsprechende Activity gestartet. Damit hätten wir die MainActivity durch. Weiter gehts….

3.2 Chart Activity

public class ChartActivity extends Activity implements OnChartGestureListener {
     private LineChart chart;
     private ChartData chartdata = new ChartData();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.chart_activity);
 
         chart = (LineChart) findViewById(R.id.chart);

         chart.getXAxis().setPosition(XAxisPosition.BOTTOM);;
         chart.getXAxis().setTextSize(7f);
         chart.getAxisLeft().setEnabled(false);
         chart.getAxisRight().setEnabled(false);
         chart.setDescription(null);
         chart.setScaleEnabled(false);
         chart.setHighlightIndicatorEnabled(false);
         chart.setOnChartGestureListener(this);
         chart.setData(chartdata.SetChartData(0));
         chart.invalidate();
     }
     @Override
     public void onChartLongPressed(MotionEvent me) {
     }

     @Override
     public void onChartDoubleTapped(MotionEvent me) {
          AlertDialog.Builder builder = new AlertDialog.Builder(this);
          builder.setTitle("Daten für den " + chartdata.Date)
               .setMessage(chartdata.getInfo())
               .setCancelable(false)
               .setNeutralButton("Schließen",new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
               }
          });
          AlertDialog alert = builder.create();
          alert.show();
     }

     @Override
     public void onChartSingleTapped(MotionEvent me) {
     }

     @Override
     public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX,
     float velocityY) {
          if (velocityX > velocityY && (velocityX - velocityY) > 1000){ //Rechts
               chart.setData(chartdata.SetChartData(-1));
          }
         if (velocityY > velocityX && (velocityY - velocityX) > 1000){ //Links
              chart.setData(chartdata.SetChartData(1));
         }
         if (chartdata.isEmpty == 0){
              Toast.makeText(getApplicationContext(),"Keine weiteren Daten vorhanden.",              Toast.LENGTH_SHORT).show();
         }
         chart.invalidate();
     }

     @Override
     public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
     }
}

Die Chart Activity Klasse kümmert sich um die richtige Darstellung des Diagramms. Das Diagramm selbst ist ein Objekt vom Typ LineChart welches wir direkt am Anfang erstellen. Für die Daten haben wir eine extra Klasse gemacht, dieses Objekt erstellen wir direkt dahinter „chartdata“. In der „onCreate“ Methode initialisieren wir erst das „chart“ Objekt über die ID vom Layout. Danach folgen die optischen Anpassungen.
– Die X-Achse wird nach unten gesetzt
– Die Schriftgröße der X-Achse wird gesetzt
– Die Achsen links und rechts werden deaktiviert
– Die Beschreibung des Diagramms wird auf null gesetzt
– Das scrollen (zoomen) ins Diagramm wird deaktiviert
– Das Markieren der Werte wird deaktiviert

Diese Einstellungen sind natürlich frei wählbar und können nach belieben eingesetzt werden. Danach wird ein „Listener“ eingesetzt den wir in die Klasse implementieren (OnChartGestureListener). Danach implementieren wir die fünf Methoden der Klasse. Wir werden aber nur zwei Methoden nutzen „onChartDoubleTapped“ und „onChartFling“. Über die Methode „setData“ setzten wir die Werte in das Diagramm. Die Werte kommen über die Methode „SetChartData“ unserer Klasse „chartdata“ und liefern die Werte als ein LineData Objekt. Aber dazu später mehr.Als letztes wird die Methode „invalidate“ aufgerufen die jedesmal bei Änderung des Diagramms gestartet werden muss. In der „onChartDoubleTapped“ Methode behandeln wir den „Doppelklick“ auf das Diagramm. Wie oben gesehen öffnet sich hier ein kleines Fenster mit paar Informationen über den angezeigten Tag. Diese Informationen werden über ein AlertDialog Objekt dargestellt. Wir erstellen zuerst einen sogennaten Builder und verpassen ihm einen Titel „Daten für den …“.Das Datum erhalten wir über die Variable „Date“ aus der Klasse ChartData. Den Inhalt der Nachricht bekommen wir über die Methode „getInfo()“. Danach schalten wir „die Schließung“ der Nachricht aus und erstellen einen Button der uns diese Aufgabe übernimmt. Am Ende erstellen wir die Box und lassen sie uns über die Methode „show“ darstellen. Die Methode „onChartFling“  berechnet (glaube ich ist schon länger her) die Dauer der Wischbewegung von Punk 1 (X/Y Koordianten) bis zum Punkt 2 (X/Y Koordinaten). Hier habe ich das so gelöst das wenn die Koordinate X größer Koordinate Y ist und die Differenz dieser Punkte größer 1000 ist, eine Wischbewegung nach Rechts erfolgt. Wieso? Ich habe absolut keine Ahnung mehr. Ich glaube ich habe mir damals die Koordinaten in das Log gespeichert und daraus dieses entnommen. Ich vermute hier wird nicht die Entfernung der Punkte zueinander überprüft sondern eben die Dauer bis man von Punkt 1 bis Punkt 2 gelangt. Somit ist es egal wie groß die Wischbewegung ist, viel wichtiger ist die Dauer. Aber je länger die Wischbewegung ausfällt desto größer ist die Zeit die man zwischen den Punkten zurückliegt.Egal! Erfolgt eine Wischbewegung nach Rechts wird über die Methode „setChartData“ mit dem Parameter „-1“ ein Tag zurück angezeigt mit einer Bewegung nach links eben ein Tag vor. Haben wir zu dem gewünschten Tag keine Daten (das wird über die Variable „isEmpty“ gecheckt) erfolgt eine entsprechende Meldung. Am Ende,wie oben bereits erwähnt, müssen wir die „invalidate“ Methode aufrufen.

3.3 Stats Activity

public class StatsActivity extends Activity {
 
     private TextView count,maxtemp,mintemp;
     private JSONObject response = new JSONObject();
     private JSONObject input = new JSONObject();
     @Override
     protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.stats_activity);
 
          count = (TextView)findViewById(R.id.stats_txt_count);
          maxtemp = (TextView)findViewById(R.id.stats_txt_maxtemp);
          mintemp = (TextView)findViewById(R.id.stats_txt_mintemp);
 
          getData();
     }
 
     @SuppressWarnings("unchecked")
     private void getData(){
          input.put("ID","TEMP");
          input.put("COMMAND","STATS");
          try {
              response = new TCPConnect().execute(input).get();
              count.setText(response.get("COUNTTEMP").toString());
              JSONObject maxTemp = (JSONObject) response.get("MAXTEMP");
              String maxTempS = maxTemp.get("TEMP").toString()
                   + " \u2103 am "
                   + maxTemp.get("DATE").toString() 
                   + " um " + maxTemp.get("TIME");
              maxtemp.setText(maxTempS);
              JSONObject minTemp = (JSONObject) response.get("MINTEMP");
              String minTempS = minTemp.get("TEMP").toString() 
              + " \u2103 am "
              + minTemp.get("DATE").toString()
              + " um " + minTemp.get("TIME");
              mintemp.setText(minTempS);
          } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
          } catch (ExecutionException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
     }
}

Die Statistik Activity zeigt uns die Anzahl der gespeicherten Datensätze an, sowie die jemals maximale und minimale gemessene Temperatur. Dazu brauchen wir drei TextViews. Dazu kommen noch zwei JSON Objekte.Das „response“ Objekt wird uns die Antwort vom Server liefern. Das „input“ Objekt enthält die Anfrage an den Server. Also initialisieren wir in der „onCreate“ Methode zuerst die Views und rufen die „getData()“ Methode auf. Diese verarbeitet zunächst das JSON „input“ Objekt und packt die richtige ID sowie das richtige Kommando hinein.Nun wird über die Klasse „TCPConnect“ versucht eine entsprechende Antwort vom Server zu bekommen. Haben wir die Antwort, im Form eines JSON Objekts, dann entnehmen wir nach und nach die Informationen heraus und füllen damit unsere TextViews. In der Methode habe ich noch kein Error Handling eingebaut, ich meine es ist ehrlich gesagt auch nicht unbedingt notwendig. Höchsten sollte zum Bespiel ein Toast erscheinen wenn irgendwas nicht richtig gelaufen ist.

3.4 TCPConnect

public class TCPConnect extends AsyncTask<JSONObject,Void,JSONObject>{
 
     private Socket socket = null;
     private ObjectOutputStream out = null;
     private ObjectInputStream in = null;
 
     private String ip;
     private int port;
     private JSONObject response = null;
 
     @Override
     protected void onPreExecute() {
         ip = "IP-Adresse";
         port = Portnummer;
     }
     @SuppressWarnings("unchecked")
     @Override
     protected JSONObject doInBackground(JSONObject...Command) {
          try { 
               socket = new Socket(ip,port);
          } catch (IOException e) {
                return (JSONObject) response.put("ERR","Fehlgeschlagen!"                     + e.toString());
          }
 
          try{
               out = new ObjectOutputStream(socket.getOutputStream());
               out.writeObject(Command[0]);
 
               in = new ObjectInputStream(socket.getInputStream());
               response = (JSONObject) in.readObject();
 
          } catch (ClassNotFoundException e) {
               e.printStackTrace();
          } catch (StreamCorruptedException e) {
               e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
               try {
                    out.close();
                    in.close();
                    socket.close();
                    System.out.println("Connection closed");
          } catch (IOException e) {
               e.printStackTrace();
          }
      }
      return response;
   }
}

Diese Verbindung müssten einige von euch bereits kennen. Im Gegensatz zu anderen Projekten wo wir mithilfe von Strings die Informationen über das Netzwerk verschickt haben, werden diesmal direkt JSON Objekte verwendet. Deshalb müssen wir der AsyncTask Klasse mitteilen das wir als Sender und Empfänger JSON Objekte verwenden. Danach erstellen wir ein neues Objekt vom Typ Socket. Es folgt ein Objekt vom Typ ObjectOutputStream „out“ welches wir dann Richtung Server schicken. Das Objekt vom Typ ObjectInputStream „in“ verwenden wir für die Antwort vom Server. Jetzt folgt ein String „ip“ und ein Integer „port“. Als letztes kommt ein JSON Objekt welches die Klasse dann im Normalfall mit den gewünschten Informationen zurückliefert. Die „onPreExecute“ Methode wird zuerst aufgerufen. Hier müsst ihr entsprechende Informationen hinterlassen (IP und Port). Die „doInBackground“ Methode erstellt die Verbindung zum Server. Zuerst wird ein neues Socket aufgebaut. Danach wird über die Methode „write“ das JSON Objekt welches wir der Klasse „doInBackground“ übergeben haben an den Server verschickt. Über den InputStream holen wir uns die Antwort vom Server und schreiben diese in das JSON Objekt „response“ hinein. In beiden Fällen müssen wir die Objekte aus den Streams als JSON Objekte „casten“. Aber das ist klar schließlich weiß der Server ja nicht um welche Art von Objekten es sich handelt, Am Ende werden die Output und Input Streams sowie der Socket geschlossen. Der letzte Schritt liefert uns das gefüllte JSON Objekt „response“ zurück.

3.5 ChartData

public class ChartData {
     private ArrayList<String> xAxisData;
     private LineDataSet yAxisData;
 
     private JSONObject JsonData = null;
     public String Date = null;
     public int isEmpty;
 
     public LineData SetChartData(int direction){
          GetDate(direction);
          GetJsonDay();
          if (isEmpty == 1){
               SetXAxisData();
               SetYAxisData();
          }else{
               isEmpty = 0;
               GetDate(-direction);
          }
          return new LineData(xAxisData,yAxisData);
     }
 
     private String GetDate(int direction){
          SimpleDateFormat sdf = new SimpleDateFormat
                         ("yyyy-MM-dd",java.util.Locale.getDefault());
          Calendar c = Calendar.getInstance();
          if (direction != 0){
               try {
                    c.setTime(sdf.parse(Date));
               } catch (ParseException e) {
                    e.printStackTrace();
               }
               c.add(Calendar.DATE,direction);
               Date = sdf.format(c.getTime());
          }else{
               Date = sdf.format(c.getTime());
          }
          return Date;
     }
 
     private void SetYAxisData() {
          JSONArray JsonArr = (JSONArray)JsonData.get(Date);
          ArrayList<Entry> TempData = new ArrayList<Entry>();
          for (int i = 0;i < JsonArr.size();i++){
               JSONObject JsonObj2 = (JSONObject)JsonArr.get(i);
               TempData.add(new Entry
                    (Float.valueOf((String) JsonObj2.get("TEMP")),i));
          }
          yAxisData = new LineDataSet(TempData,null);
          yAxisData.setLabel(Date);
          yAxisData.setDrawFilled(true);
          yAxisData.setValueTextColor(Color.BLUE);
     }

     private void SetXAxisData(){
          xAxisData = new ArrayList<String>();
          for (int i = 0;i < 24;i+=3){
               xAxisData.add(i + ":00");
          }
      }
 
      @SuppressWarnings("unchecked")
      private void GetJsonDay(){
           isEmpty = 1;
           JSONObject JsonToServer = new JSONObject();
           JsonToServer.put("ID","TEMP");
           JsonToServer.put("COMMAND","TEMPFORDAY");
           JsonToServer.put("DATE",Date);
           try {
            JsonData = new TCPConnect().execute(JsonToServer).get();
            if (JsonData.get(Date).toString().equals("[]")) isEmpty = 0;
           } catch (InterruptedException e) {
            isEmpty = 0;
           } catch (ExecutionException e) {
            isEmpty = 0;
           }
      }
 
      public String getInfo(){
           String info = "";
           info += "Höchste Temperatur: " 
                     + String.valueOf(yAxisData.getYMax()) + "\n";
           info += "Niedrigste Temperatur: " 
                     + String.valueOf(yAxisData.getYMin()) + "\n";
           info += "Durchnitt. Temperatur: " 
                   + String.valueOf
           (yAxisData.getYValueSum()/yAxisData.getEntryCount()) + "\n";
           return info;
      }
}

Die letzte Klasse ist wohl mit Abstand die wichtigste. Hier werden die Daten für das Diagramm erstellt. Zuerst brauchen wir eine ArrayListe für die X Werte. Die X-Werte sind vom Typ „String“ die Liste nennen wir „xAxisData“. Für die Y-Achse brauchen wir die Werte im Form einen LineDataSet Objekts. Dazu kommt ein JSONObjekt, ein String für das Datum sowie ein Integer der überprüfen soll ob es überhaupt Daten zum verarbeiten gibt. Wie man sehen kann gibt es nur zwei Methoden die „public“ sind also von anderen Klassen erreichbar. Zum einen „SetChartData“ zum anderen getInfo(). Kümmern wir uns zuerst um die „SetChartData“ Methode. Diese liefert uns im besten Fall die gewünschten Informationen im Form eines LineData Objekts welches wir dann im Diagramm darstellen können. Als Parameter erwartet die Methode einen Integer „direction“. Ich werde schreiben welche Methode aufgerufen wird und dann die Methode beschreiben. Denn hier werden alle anderen „privaten“ Methoden gebraucht. Also zuerst wird die Methode „GetDate“ aufgerufen welcher wir den Integer „direction“ übergeben:
GetDate:
Diese Methode liefert uns das Datum für welches wir die Temperaturwerte anzeigen lassen wollen. Das Datum wird im Format „yyyy-MM-dd“ also „Jahr-Monat-Tag“ dargestellt und wird über das Objekt „Calendar“ gespeichert. Der Integer „direction“ entscheidet in diesem Fall ob wir das momentane Datum oder ein Tag vor oder zurück haben wollen. Ist „direction“ also gleich 0 dann wird einfach das aktuelle Datum von der Methode zurückgeliefert in Form eines Strings „Date“. Ist „direction“ ungleich 0 (zb. durch eine Wischbewegung wollen wir ein Tag zurück) dann wird zuerst in das Calender Objekt das Datum von dem String „Date“ gesetzt um dann mithilfe der Methode „add“ (1 oder -1) das neue Datum zu berechnen und den String „Date“ zu überspielen.
GetJsonDay:
Diese Methode folgt nach der GetDate Methode. Zu diesem Zeitpunkt ist der String „Date“ mit dem gewünschtem Datum gesetzt. Zu diesem Datum liefert uns diese Methode die Temperaturwerte. Zuerst setzten wir den Integer „isEmpty“ auf 1 was bedeutet das noch alles im grünen Bereich ist. Ich weiß eig. müsste das umgekehrt sein also 1 = leer und 0 = voll aber das habe ich wohl vercheckt (total bescheuert). Wie auch immer, danach erstellen wir ein neues JSON Objekt welches wir mit den richtigen Parameter füllen sowie dem Datum. Jetzt holen wir uns die Informationen über die Klasse „TCPConnect“ vom Server und speichern diese in das JSON Objekt „JsonData“. Wenn das JSON Objekt über den Parameter „Date“ nur [] enthält, dann haben wir keine Temperaturwerte zu dem mitgegebenen Datum erhalten. In diesem Fall setzen wir die Variable „isEmpty“ auf 0. Auch bei möglichen Exceptions wird die Variable auf 0 gesetzt. Verlief alles normal dann enthält das JSONObjekt „JsonData“ die gewünschten Werte.

Wir springen nochmal kurz zu der Methode „SetChartData“ zurück. Hier wird bevor wir weitere Methoden aufrufen, erst überprüft ob isEmpty = 1 ist. Wenn es der Fall ist können wir die Achsen mit den Werten füllen. Ist es nicht der Fall und wir haben keine Daten erhalten (isEmpty = 0) dann rufen wir die GetDate(-direction) Methode auf um uns das zuletzt funktionierende Datum in die Variable Date zu speichern. Wenn aber alles passt werden zwei weitere Methoden aufgerufen.
SetYAxisData:
Diese Methode füllt uns das LineDataSet Objekt mit den entsprechenden Temperaturwerten. Zuerst aber erstellen wir ein JSONArray aus den Informationen über die ID „date“ vom JSON Objekt „JsonData“. Danach folgt eine weitere ArrayListe diesmal aber mit Elementen vom Typ „Entry“ die das Objekt „LineDataSet“ benötigt. Aus den vorherigen Teil wissen wir wie das JSON Objekt aufgebaut ist. Das Array besitzt einzelne Objekte welche die Temperaturwerte enthalten. Mit einer For-Schleife gehen wir also diese Objekte des Arrays durch und holen uns die einzelnen Objekte raus und speichern diese in das JSONObjekt „JsonObj2“. Das passiert innerhalb der Schleife wo jedesmal das JSONObjekt mit neuen Werte überschrieben wird. Diese Werte „adden“ wir zu der ArrayListe indem wir neue Objekte vom Typ Entry erstellen. Dem „Entry“ Objekt übergeben wir die Temperatur als Float indem wir diese über die ID „Temp“ aus dem JSON Objekt herausholen. Wird die Schleife beendet dann befinden sich alle Temperaturwerte aus dem JSON Array jetzt in dem Array „TempData“. Mit diesem Array lässt sich ein neues Objekt vom Typ „LineDataSet“ erstellen. Danach folgt noch das Label, hier setzten wir das entsprechende Datum fest. Danach teilen wir dem Objekt mit das die Achse ausgefüllt werden und mit welcher Farbe dies geschehen soll. Am Ende ist die Y-Achse fertig.
SetXAxisData:
Die X-Achse zeigt nur die Uhrzeit zu dem aufgenommenen Wert an. Deswegen brauchen wir nur zuerst ein neues ArrayList dem Objekt xAxisData zuweisen. Mithilfe einer For-Schleife können wir dann die Liste mit den entsprechenden Uhrzeiten füllen. In diesem Fall habe ich die Temperatur alle drei Stunden aufgenommen (+3). Solltet ihr andere Zeiten genommen haben müsst ihr hier einfach die For-Schleife anpassen.

Zurück zu der „SetChartData“ Methode. Wenn alles normal durchgelaufen ist dann können wir am Ende der Methode ein neues Objekt vom Typ „LineData“ zurückliefern, welches mithilfe der Werte von der Y- und X -Achse erstellt werden konnte. Die letzte Methode „getInfo“ liefert uns ja die Werte für die MessageBox. Hier wird einfach nur ein String „info“ mit den entsprechenden Informationen gefüllt. Die max. min. Temperaturen können wir über die Methoden „getYMax“ und „getYMin“ holen. Die durchschnitt. Temperatur berechnen wir aus der Summe der Werte der Y-Achse (getYValuesSum) und der Anzahl der Werte von der X-Achse (getEntryCount).

 

Damit wäre das Projekt „RaspberryPi – Temperatur messen und in einer Android Application anzeigen“ fertig und beendet. Der letzte Teil ist jetzt doch bisschen länger geworden. Ich weiß nicht ob ich alles so verständlich schreiben konnte wie ich es gern tun würde. Ich hoffe aber das dieses Projekt jemanden von euch zu weiterer Arbeit motiviert. Ich habe das Projekt zusätzlich als Download bereitgestellt (nur die Android Application). Dann kann man hoffentlich besser nachvollziehen was ich da überhaupt fabriziert habe. Ich wünsche viel Spaß beim basteln.

  • TempLooker.zip – Einfach unter Eclipse – Import – Existing Projets i.. – Select Archive File

TEIL 1TEIL 2TEIL 3

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.