Android App Entwicklung: ESP Controller ansprechen #2

Im letzten Tutorial habe ich erläutert wie man eine Verbindung zu einem ESP Controller aufbaut und Daten sendet & empfängt.

Ausführen der App - Absenden eines Request an den WittyCloud
Ausführen der App – Absenden eines Request an den WittyCloud

Nun möchte ich gerne erläutern wie man den Fotowiderstand ausliest und an die AndroidApp sendet.

Auslesen eines Fotowiderstandes und anzeigen des Wertes in einer AndroidApp

 

Als Microcontroller habe ich den WittyCloud verwendet, dieser bietet sich an da der Controller neben einem ESP12 Chip auch über einen Fotowiderstand und einem NeoPixel verfügt.

Als Grundlage möchte ich die AndroidApp aus dem letzten Tutorial Android App Entwicklung: ESP Controller ansprechen #1 verwenden.

Wie auch im letzten Tutorial möchte ich den Aufbau Schritt für Schritt erläutern und zum Schluss haben wir eine lauffähige Android App.

Solltest du im nachfolgenden Tutorial Fehler finden, oder Fragen haben, so kannst du dich gerne per E-Mail oder über das Kontaktformular an mich wenden.

Schaltung

Für dieses Tutorial benötigst du einen ESPx mit einem Fotowiderstand, wie bereits erwähnt verwende ich den WittyCloud dieser hat bereits einen Fotowiderstand verbaut.

Witty Cloud
Witty Cloud

Wenn du diesen nicht besitzt ist das nicht schlimm, es kann jeder beliebige ESPx Controller verwendet werden welcher über min. einen analogen Pin verfügt.

Aufbau der Schaltung für einen NodeMCU

In diesem Abschnitt möchte ich nun beschreiben wie du eine Schaltung mit einem NodeMCU und einem Fotowiderstand aufbaust.

Du benötigst für diese Schaltung folgende Bauteile:

  • 1x NodeMCU,
  • 1x Fotowiderstand,
  • 1x 10kOhm Widerstand,
  • 4x Breadboardkabel,
  • 1x Breadboard mit 400 Pins

Anschluß & Schaltung

Der Fotowiderstand verfügt über 2 Beinchen, eines von diesen wird mit dem 10kOhm Widerstand und das andere mit 3,3V verbunden. Des Weiteren wird zwischen dem Fotowiderstand und dem Widerstand ein Breadboardkabel mit dem analogen Pin A0 verbunden.

Schaltung - NodeMCU mit Fotowiderstand
Schaltung – NodeMCU mit Fotowiderstand

 

NodeMCU mit Fotowiderstand
NodeMCU mit Fotowiderstand

Quellcode

Hier nun ein einfacher Sketch um die Funktionalität der Schaltung zu testen.

#define FOTORESISTOR A0
void setup() {
   Serial.begin(9600);
}   

void loop() {
   int value = analogRead(FOTORESISTOR);    //Ließt den Wert des Sensors vom analogen PIN A0
   Serial.println(value);
   delay(750);
}

Schritt 1 – Auslesen der Werte des Fotowiderstandes

Als erstes wollen wir nun die Werte des Fotowiderstandes auslesen. Dazu erzeugen wir uns eine neue Funktion in unserem bestehenden Sketch aus dem ersten Tutorial.

void callFotoresistor(){
  //Ließt den Wert des Fotowiderstandes vom analogen PIN A0
  int value = analogRead(FOTORESISTOR);
  //absenden des Wertes an den verbundenen Client
  sendResult("{\"msg\": \""+String(value)+"\"}");
}

Zusätzlich müssen wir diese Methode dem Server bekannt geben,
damit wir aus der Android App die Adresse „http://<<IP-Adresse>>/fotoresistor“ aufrufen können.

Dazu erweitern wir die Setup Funktion um folgenden Eintrag:

...
server.on("/greeting", callGreeting);
server.on("/fotoresistor", callFotoresistor);
     
server.begin(); // Starten des Servers.
...

Schritt 2 – Auswerten der JSON Daten

Nachdem wir nun die Werte senden können, müssen wir diese noch auswerten. Die Daten empfangen wir im JSON Format, um aus diesem Datenformat die Schlüssel/Wertepaare auszulesen verwende ich die Bibliothek Google Gson.

Ein einfacher JUnitTest

Wie diese Bibliothek funktioniert möchte ich in einem kurzen und knackigen JUnit Testcase erläutern.

Es wird ein JSON String mit {„msg“:“Hello from ESP8266!“} der Gson Bibliothek übergeben und in die Klasse „SimpleData“ transformiert.

package de.draegerit.simpleGsonProject;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;

import com.google.gson.Gson;

public class ReadJsonData {

   //Beispiel JSON mit einem Schlüssel "msg" und dem Wert "Hello from ESP8266!"
   private static final String JSON_DATA = "{\"msg\":\"Hello from ESP8266!\"}";

   @Test
   public void readSimpleData() {
      //erzeugen einer Gson Instanz
      Gson gson = new Gson();
      //Mit der Methode "fromJson" wird das JSON Datenformat in die übergebene Klasse umgewandelt.
      //Es ist wichtig das für jeden Schlüssel im JSON ein Feld in der Klasse existiert und das der Datentyp stimmt.
      SimpleData data = gson.fromJson(JSON_DATA, SimpleData.class);
		
      //Testen ob die Daten erfolgreich umgewandelt wurden.
      assertNotNull(data);
      //Der Wert in unserer Klasse "SimpleData" sollte "Hello from ESP8266!" sein.
      assertEquals("Hello from ESP8266!", data.getMsg());
   }

   //Eine einfache Klasse zum testen des JSON Formates.
   class SimpleData {
	
      //Feld zum speichern der Nachricht.
      private String msg;

      public String getMsg() { return msg; }
      public void setMsg(String msg) { this.msg = msg; }
  }
}

Einbinden der Bibliothek in das Android Projekt

Bevor wir diese Bibliothek verwenden können müssen wir diese in unser BuildScript einbauen. Dazu öffnen wir die Datei „build.gradle (Module: app)“. Im unteren Abschnitt der Datei finden wir die „dependencies“ dieses sind die Abhängigkeiten für unser Projekt.

Dort fügen wir die nachfolgende Zeile hinzu und klicken danach auf den Link „Sync Now“ (gelber Balken, oben links).

implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'

Es wird nun die Bibliothek aus dem Internet geladen und das Projekt gebaut.

Wenn diese Schritt erfolgreich ausgeführt wurde kann mit der Implementation begonnen werden.

Umwandeln des JSON Formates

Wir erhalten vom ESP ein JSON mit eine Schlüssel / Wertepaar, der Schlüssel lautet in unserem Beispiel „msg“. D.h. wir erzeugen uns zunächst eine Klasse welche später unser JSON repräsentieren soll.

package de.draegerit.esptutorialapp;

public class EspMessage {
    
   private String msg;

   public String getMsg() { return msg; }

   public void setMsg(String msg) { this.msg = msg; }
}

Da wir bereits eine Funktion haben um unsere Daten an den ESP zu senden wollen wir diese nutzen und auch auf das empfangen reagieren. Wir ja nun zwei Anwendungsfälle, einmal das eine Willkommensnachricht abgesendet wird und einmal nun unseren Fotowiderstand (und später wollen wir noch unseren NeoPixel steuern).

Hier bietet es sich an ein ENUM zu erzeugen welcher Werte für unsere „Actions“ enthält. Wir bauen hier nun noch mit ein das die Adresse enthalten ist und ob die Aktionen Parameter übergeben kann.

package de.draegerit.esptutorialapp;

public enum EAction {
   GREETING("greeting?text=", true), FOTORESISTOR("/fotoresistor", false);

   private String adress;
   private boolean hasParameter;

   EAction(String adress, boolean hasParameter) {
       this.adress = adress;
       this.hasParameter = hasParameter;
   }

   public String getAdress() { return adress; }

   public boolean isHasParameter() { return hasParameter; }
}

Und dieses ENUM übergeben wir unserem Konstruktor der Klasse „RequestAsyncTask“. Da wir vom ESP Controller einen Wert erwarten und keinen senden wollen schreiben wir uns einen neuen Konstruktor welcher keinen zusätzlichen Text erwartet. (Wir könnten auch ein „null“ anstelle des Textes setzen.)

private EAction action;
public RequestAsyncTask(String ipAdresse, String text, EAction action) {
   this.ipAdresse = ipAdresse;
   this.text = text;
   this.action = action;
}

public RequestAsyncTask(String ipAdresse, EAction action) {
   this(ipAdresse,null,action);
}

Zusätzlich müssen wir unsere bestehende Funktion für den Aufruf der Willkommensnachricht anpassen. In diesem Zuge benennen wir diese um von „sendRequest“ in „sendWellcomeGreetingRequest“.

private void sendWellcomeGreetingRequest(String ipAdresse, String text) {
   RequestAsyncTask connectionAsyncTask = new RequestAsyncTask(ipAdresse, text, EAction.GREETING);
   connectionAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

Nun passen wir unseren Aufruf in der Funktion „doInBackground“ an damit wir unterscheiden können ob wir eine Willkommensnachricht absenden oder aber einen Wert des Fotowiderstandes erhalten wollen.

StringBuffer urlBuffer = new StringBuffer();
urlBuffer.append("http://");
urlBuffer.append(ipAdresse);
urlBuffer.append("/");
urlBuffer.append(action.getAdress());
if(action.isHasParameter()){
  switch(action){
     case GREETING:
        urlBuffer.append(text);
     break;
  }
}

Layout anpassen

Nun wollen wir einen zweiten Button erzeugen und diesem in der Funktion „onClick“ die Aktion zuweisen einen Request an den ESP Controller zu senden einen Wert des Fotowiderstandes auszulesen und zurück zu liefern.

Unser Layout „activity_main.xml“ erweitern wir wiefolgt:

<TableRow
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="15dp">
   <Button
      android:id="@+id/wellcomeBtn"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_span="2"
      android:text="@string/btnWellcomeMsg" />
</TableRow>

<TableRow
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="15dp">
   <Button
      android:id="@+id/fotoresistorBtn"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_span="2"
      android:text="@string/btnFotoresistorMsg" />
</TableRow>

Die Texte für die Schaltflächen werden in der Datei „strings.xml“ verwaltet, hier müssen wir nun die beiden Texte hinzufügen.

<resources>
...
  <string name="btnWellcomeMsg">Willkommensnachricht absenden</string>
  <string name="btnFotoresistorMsg">Fotowiderstand auslesen</string>
...
</resources>

Des Weiteren müssen wir (natürlich) unserem neuen Button eine Aktion zuweisen.

private Button fotoresistorBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
   ...
   fotoresistorBtn = findViewById(R.id.fotoresistorBtn);
   fotoresistorBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
         if (isNetworkAvailable()) {
          sendFotoresistorRequest(ipAdressEditText.getText().toString());
         }
      }
   });
   ...
}

Da wir unsere Funktion „doInBackground“ bereits multifunktional umgeschrieben haben brauchen wir nichts weiter tun. 

Ergebnis vom ESP Controller transformieren

Im nächsten Schritt wollen wir nun das Ergebnis (der Respond) vom ESP Controller in unser „EspMessage“ Objekt transformieren / umwandeln. Dazu nutzen wir wie eingangs erwähnt die Bibliothek Google Gson.

@Override
protected void onPostExecute(String result) {
   super.onPostExecute(result);
   Log.i("ESPTutorialApp", result);
   if (errorMsg == null && result.trim().length() > 0) {
      Gson gson = new Gson();
      EspMessage message = gson.fromJson(result, EspMessage.class);
      if (message != null) {
         textView.setText(message.getMsg());
      }
   } else if (errorMsg != null) {
      showErrorMessage(errorMsg);
   }
}

Nun wird uns der Wert des Fotowiderstandes in der App angezeigt wenn wir den Button „FOTOWIDERSTAND AUSLESEN“ betätigen.

aktueller Wert des Fotowiderstandes vom WittyCloud
aktueller Wert des Fotowiderstandes vom WittyCloud

Download

Ausblick

Nun nachdem wir den Wert lesen können wollen wir uns diesen in einem Liniendiagramm anzeigen lassen. Dazu müssen wir jedoch unser Layout (fast) komplett umstellen. Im nächsten Tutorial werden wir also eine Navigationsleiste hinzufügen und für jede bestehende Funktion eine Extra Seite einrichten. 

 

 

Schreibe einen Kommentar

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