{"id":522,"date":"2018-06-29T19:54:24","date_gmt":"2018-06-29T19:54:24","guid":{"rendered":"https:\/\/www.wpvs.de\/iot-2018\/?p=522"},"modified":"2021-05-14T10:07:03","modified_gmt":"2021-05-14T08:07:03","slug":"honeypi-7-android-app","status":"publish","type":"post","link":"https:\/\/www.iot-embedded.de\/iot-2018\/projekt-honeypi\/honeypi-7-android-app\/","title":{"rendered":"HoneyPi (7) Android-App"},"content":{"rendered":"<h2>Dashboard<\/h2>\n<p>Das Dashboard der App wurde neugestaltet und zeigt nun Echtdaten anstatt Dummy-Daten an. Ganz oben wird die M\u00f6glichkeit geboten, den Channel \u00fcber ein Dropdown-Men\u00fc (in Android <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/controls\/spinner\">Spinner<\/a> genannt) auszuw\u00e4hlen. Dadurch kann sich der Benutzer das Dashboard f\u00fcr jeden Bienenstock separat anschauen. Das Dashboard zeigt nun die aktuellen Werte aller Sensoren und darunter eine Honigertragstabelle an. Jede Spalte der Tabelle ist auf- und absteigend sortierbar. Hierf\u00fcr wurde die externe Bibliothek <a href=\"https:\/\/github.com\/ISchwarz23\/SortableTableView\">SortableTableView<\/a> verwendet. Leider zeigt die Honigertragstabelle falsche Werte an, da die W\u00e4gezellen nicht richtig eingestellt waren und somit fehlerhafte Messwerte lieferten. Nachfolgende Abbildung zeigt das Dashboard.<\/p>\n<h2><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-527 alignnone\" style=\"font-size: 16px\" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-409x1024.jpg\" alt=\"\" width=\"300\" height=\"751\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-409x1024.jpg 409w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-120x300.jpg 120w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-768x1921.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-614x1536.jpg 614w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-819x2048.jpg 819w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_2018-06-25-16-55-30-scaled.jpg 1024w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/h2>\n<h2>AQI-Informationsseite<\/h2>\n<p>Falls der Sensor zum Messen der Luftqualit\u00e4t mit dem ThingSpeak-Konto verbunden wurde, erscheint ein Informationssymbol. Wenn dieses angeklickt wird, \u00f6ffnet sich ein Informationsdialog \u00fcber Luftqualit\u00e4t und dem Air Quality Index (AQI). Siehe hierzu folgende Abbildung.<\/p>\n<h2><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-540\" style=\"font-size: 16px\" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139-576x1024.jpg\" alt=\"\" width=\"300\" height=\"533\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180629-221139.jpg 1080w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/h2>\n<h2>Lade- und Fehlerseiten<\/h2>\n<p>Au\u00dferdem wurden nun zur besseren Usability Lade- und Fehlerseiten eingebaut, die dem Benutzer anzeigen, ob die Daten geladen werden, keine Daten verf\u00fcgbar sind oder keine Internetverbindung besteht. Nachfolgende drei Lade- bzw. Fehlerseiten wurden in der App integriert.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-529 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251-576x1024.jpg\" alt=\"\" width=\"230\" height=\"409\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170251.jpg 1080w\" sizes=\"(max-width: 230px) 100vw, 230px\" \/> <img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-530 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549-576x1024.jpg\" alt=\"\" width=\"230\" height=\"409\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170549.jpg 1080w\" sizes=\"(max-width: 230px) 100vw, 230px\" \/> <img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-531 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558-576x1024.jpg\" alt=\"\" width=\"230\" height=\"409\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-170558.jpg 1080w\" sizes=\"(max-width: 230px) 100vw, 230px\" \/><\/p>\n<h2>Benutzerdefinierter Zeitraum<\/h2>\n<p>Auf den Detailseiten der einzelnen Messarten funktioniert nun auch der Tab \u201eBENUTZERDEFINIERT\u201c. Hierf\u00fcr kann der Benutzer ein beliebiges Start- und Enddatum aus der Vergangenheit ausw\u00e4hlen. Anschlie\u00dfend wird die \u00fcbliche Seite mit dem Liniendiagramm sowie H\u00f6chst-, Tiefst- und Durchschnittswert f\u00fcr diesen Zeitraum angezeigt. Es ist auch m\u00f6glich, wie auf nachfolgender Abbildung zu sehen ist, das Start- und Enddatum \u00fcber einen sogenannten <a href=\"https:\/\/developer.android.com\/reference\/android\/widget\/DatePicker\">DatePicker<\/a> auszuw\u00e4hlen.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-532 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816-576x1024.jpg\" alt=\"\" width=\"300\" height=\"534\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-171816.jpg 1080w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<h2>Einstellungsseite<\/h2>\n<p>Die letzten \u00c4nderungen in der Android-App waren die Einrichtung einer Einstellungsseite. Folgende Einstellungen sind m\u00f6glich:<\/p>\n<ol>\n<li>Den Bienenstock f\u00fcr das Dashboard ausw\u00e4hlen.<\/li>\n<li>Den Aktualisierungsinterval f\u00fcr die Detailseiten einstellen (1 bis 60 Minuten).<\/li>\n<li>Ein Standardstartdatum f\u00fcr den benutzerdefinierten Tab einstellen.<\/li>\n<li>Ein Standardenddatum f\u00fcr den benutzerdefinierten Tab einstellen.<\/li>\n<li>Die M\u00f6glichkeit, aus allen Fields aller Channels des ThingSpeak-Kontos, auszuw\u00e4hlen, welche Fields in der App angezeigt werden sollen.<\/li>\n<li>Die Messart aller ausgew\u00e4hlten Fields \u00e4ndern (m\u00f6gliche Messarten: Temperatur, Luftfeuchtigkeit, Luftdruck, Luftqualit\u00e4t, Gewicht oder keine spezifische Messart).<\/li>\n<li>Die Channels und Fields mit dem ThingSpeak-Konto synchronisieren. Dies kann der Benutzer bet\u00e4tigen, wenn er z. B. \u00c4nderungen am ThingSpeak-Konto vorgenommen hat und diese in der App sichtbar werden sollen.<\/li>\n<li>Eine Schaltfl\u00e4che zum \u00d6ffnen der \u00dcber-HoneyPi-Seite. Hier werden Kontaktinfos, Credits und Copyright angezeigt.<\/li>\n<li>Eine Schaltfl\u00e4che zum Abmelden aus der App. Danach erscheint wieder die Loginseite zum Eingeben des User-API-Keys.<\/li>\n<\/ol>\n<h6>Problem bei der Einstellungsseite<\/h6>\n<p>Die sechste Einstellung hat etwas mehr Zeit gekostet, da die einzelnen Elemente (Fields) zum Bearbeiten dynamisch erzeugt werden m\u00fcssen. Au\u00dferdem soll sich beim Anklicken eines Elements ein Dialog \u00f6ffnen, in dem schlie\u00dflich die richtige Messart ausgew\u00e4hlt werden kann. Hierf\u00fcr kam zun\u00e4chst die Klasse <a href=\"https:\/\/developer.android.com\/reference\/android\/preference\/ListPreference\">ListPreference<\/a> von Android in Frage. Dies kann jedoch nur statisch f\u00fcr eine bekannte Anzahl an Fields verwendet und einzeln in der preferences.xml angegeben werden. Nach einigen fehlgeschlagenen Versuchen ListPreference-Elemente dynamisch im Java-Code zu erzeugen, musste eine andere L\u00f6sung gefunden werden.<\/p>\n<h6>L\u00f6sung des Problems<\/h6>\n<p>Die neue L\u00f6sung besteht nun daraus, dass beim Anklicken der Schaltfl\u00e4che zum \u00c4ndern der Messart in den Einstellungen eine neue Seite erscheint, auf der jedes aktivierte Field in einer <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/layout\/listview\">Android-ListView<\/a> angezeigt wird und selbst jeweils einen OnClickListener besitzt, dessen Callback-Methode ausgef\u00fchrt wird, wenn das jeweilige Element\/Field angeklickt wird. Dadurch erscheint der oben erw\u00e4hnte Dialog, in dem der Benutzer die richtige Messart ausw\u00e4hlen kann. Folgendes Code-Snippet zeigt das oben beschriebene Vorgehen:<\/p>\n<pre>\/\/ Measurement types\nfinal CharSequence[] entries = {\"Temperatur\", \"Luftfeuchtigkeit\", \"Luftdruck\", \"Luftqualit\u00e4t\", \"Gewicht\", \"Keine spezifische Messart\"};\n\n\/\/ Create ArrayAdapter and custom view with dialog and radio buttons\nArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_2, android.R.id.text1, channelFieldItems) {\n     @NonNull\n     @Override\n     public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {\n          View view = super.getView(position, convertView, parent);\n          TextView textView1 = (TextView) view.findViewById(android.R.id.text1);\n          TextView textView2 = (TextView) view.findViewById(android.R.id.text2);\n\n          textView1.setText(channelFieldItems.get(position).toString());\n          textView2.setText(channelFieldItems.get(position).getType());\n          textView2.setTextColor(getResources().getColor(R.color.textColorSecondary));\n\n          view.setOnClickListener(new View.OnClickListener() {\n               @Override\n               public void onClick(View v) {\n                   AlertDialog.Builder builder = new AlertDialog.Builder(ChangeMeasurementTypePreferenceActivity.this);\n                   builder.setTitle(R.string.button_change_measurement_type_title);\n                   builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                       @Override\n                       public void onClick(DialogInterface dialog, int which) {\n                           dialog.cancel();\n                       }\n                   });\n                   builder.setSingleChoiceItems(entries, getCheckedItemNumber(channelFieldItems.get(position)), new DialogInterface.OnClickListener() {\n                       @Override\n                       public void onClick(DialogInterface dialog, int which) {\n                           \/\/ Set initial selection\n                           switch (which) {\n                               case 0:\n                                   channelFieldItems.get(position).setType(\"Temperatur\");\n                                   break;\n                               case 1:\n                                   channelFieldItems.get(position).setType(\"Luftfeuchtigkeit\");\n                                   break;\n                               case 2:\n                                   channelFieldItems.get(position).setType(\"Luftdruck\");\n                                   break;\n                               case 3:\n                                   channelFieldItems.get(position).setType(\"Luftqualit\u00e4t\");\n                                   break;\n                               case 4:\n                                   channelFieldItems.get(position).setType(\"Gewicht\");\n                                   break;\n                               default:\n                                   channelFieldItems.get(position).setType(\"\");\n                                   break;\n                           }\n                           dialog.dismiss();\n                           String channelFieldItemsString = new Gson().toJson(channelFieldItems);\n                           sharedPreferences.edit().putString(\"channelFieldItems\", channelFieldItemsString).apply();\n                           notifyDataSetChanged();\n                      }\n                   });\n\n                   AlertDialog alertDialog = builder.create();\n                   alertDialog.show();\n               }\n          });\n\n        return view;\n   }\n};<\/pre>\n<p>Durch diese L\u00f6sung war es m\u00f6glich, die Elemente dynamisch zu erzeugen und dennoch eine fast identische Optik wie bei der Verwendung von ListPreference zu erzielen. Siehe hierzu nachfolgende zwei Abbildungen.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-533 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446-576x1024.jpg\" alt=\"\" width=\"300\" height=\"533\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174446.jpg 1080w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/> <img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-534 \" src=\"http:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458-576x1024.jpg\" alt=\"\" width=\"300\" height=\"533\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458-576x1024.jpg 576w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458-169x300.jpg 169w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458-768x1365.jpg 768w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458-864x1536.jpg 864w, https:\/\/www.iot-embedded.de\/iot-2018\/wp-content\/uploads\/sites\/3\/2018\/06\/Screenshot_20180625-174458.jpg 1080w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dashboard Das Dashboard der App wurde neugestaltet und zeigt nun Echtdaten anstatt Dummy-Daten an. Ganz oben wird die M\u00f6glichkeit geboten, den Channel \u00fcber ein Dropdown-Men\u00fc (in Android Spinner genannt) auszuw\u00e4hlen. Dadurch kann sich der Benutzer das Dashboard f\u00fcr jeden Bienenstock<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/posts\/522"}],"collection":[{"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/comments?post=522"}],"version-history":[{"count":1,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/posts\/522\/revisions"}],"predecessor-version":[{"id":637,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/posts\/522\/revisions\/637"}],"wp:attachment":[{"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/media?parent=522"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/categories?post=522"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2018\/wp-json\/wp\/v2\/tags?post=522"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}