Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 26.4.2023
- // Hiotaan edellisen luennon WeatherStationFragment
- // koska teimme jsonschema2pojolla dataluokat WeatherStationin, ja silloin ei satanut vettä, luuli työkalu
- // että sateen määrä on kokonaisluku (koska tasan 0)
- Jos tulee tällainen LogCatiin:
- java.lang.NumberFormatException: Expected an int but was 0.08 at line 1 column 116 path $.d.8.v
- Tarkoittaa tämä sitä että luokassa _8.java on käytössä int-tietotyyppi, kun pitäisi olla double.
- eli esim _8.java pitäisi olla:
- public class _8 {
- @SerializedName("v")
- @Expose
- private double v;
- /**
- * No args constructor for use in serialization
- *
- */
- public _8() {
- }
- /**
- *
- * @param v
- */
- public _8(double v) {
- super();
- this.v = v;
- }
- public double getV() {
- return v;
- }
- public void setV(double v) {
- this.v = v;
- }
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(_8 .class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
- sb.append("v");
- sb.append('=');
- sb.append(this.v);
- sb.append(',');
- if (sb.charAt((sb.length()- 1)) == ',') {
- sb.setCharAt((sb.length()- 1), ']');
- } else {
- sb.append(']');
- }
- return sb.toString();
- }
- }
- Muokataan fragment_weather_stationin ulkoasua, jotta voimme tallentaa sinne tekstiä:
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".WeatherStationFragment">
- <TextView
- android:id="@+id/textView_weather_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Waiting ..."
- android:textSize="26sp" />
- </FrameLayout>
- // kokeillaan tulostaa lämpötila ulkoasussa:
- try {
- // muutetaan vastaanotettu data JSONista -> WeatherStation -luokan olioksi
- var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
- Log.d("ADVTECH", item.d.get1().v.toString() + "C")
- // asetetaan tekstimuuttuja käyttöliittymään, jossa on säätietoja
- val temperature = item.d.get1().v
- var text = "Temperature: ${temperature}℃"
- // koska MQTT-plugin ajaa koodia ja käsittelee dataa
- // tausta-ajolla omassa säikeessään eli threadissa
- // joudumme laittamaan ulkoasuun liittyvän koodin runOnUiThread-blokin
- // sisälle. Muutoin tulee virhe että koodit toimivat eri säikeissä.
- activity?.runOnUiThread {
- binding.textViewWeatherText.text = text
- }
- }
- catch(e : Exception) {
- Log.d("ADVTECH", e.message.toString())
- Log.d("ADVTECH", "Saattaa olla diagnostiikkadataa.")
- }
- // kokeillaan myös kosteusprosenttia, joka on Moodlen ohjeen mukaan numero 3 datassa:
- // asetetaan tekstimuuttuja käyttöliittymään, jossa on säätietoja
- val temperature = item.d.get1().v
- var humidity = item.d.get3().v
- var text = "Temperature: ${temperature}℃"
- text += "\n"
- text += "Humidity: ${humidity}%"
- // koska MQTT-plugin ajaa koodia ja käsittelee dataa
- // tausta-ajolla omassa säikeessään eli threadissa
- // joudumme laittamaan ulkoasuun liittyvän koodin runOnUiThread-blokin
- // sisälle. Muutoin tulee virhe että koodit toimivat eri säikeissä.
- activity?.runOnUiThread {
- binding.textViewWeatherText.text = text
- }
- ///////////////
- // MQTT OSA 2
- ///////////////
- Tehdään oma MQTT-klusteri HiveMQ-palveluun, testataan yhteydet MQTTX:llä, ja ohjelmoidaan sitten Androidiin fragment, joka osaa lähettää ja vastaanottaa tekstidataa.
- 1. Tee Harjoitus 4 ohjeen mukaisesti HiveMQ-palveluun oma klusteri, tee käyttäjätunnus, ja
- testaa datan liikkuminen (lähetys ja vastaanotto) molempiin suuntiin ohjeen mukaisella topicilla MQTTX-ohjelmalle
- 2. Tee mobile_navigation -työkalulla uusi Fragment Android-projektiin nimeltä RemoteMessageFragment. Lisää tämä fragment päävalikkoon, ja ota fragmentissa binding-layer käyttöön
- 3. Tee local.properties-tiedostoon tarvittavat muuttujat HiveMQ:ta varten (ei lainausmerkkejä mihinkään arvoon):
- HIVEMQ_BROKER=oman_klusterin_osoite
- HIVEMQ_USERNAME=oman_klusterin_käyttäjänimi
- HIVEMQ_PASSWORD=oman_klusterin_salasana
- HIVEMQ_TOPIC=koodin_käyttämä_topic
- 4. Jatketaan tästä vaiheesta tauon jälkeen
- // uusi fragmentti, RemoteMessageFragment, lisätään päävalikkoon, pohjakoodi:
- class RemoteMessageFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentRemoteMessageBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
- val root: View = binding.root
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // lisätään ulkoasuun textview ja button, jotta voimme testata MQTT:tä koodissa
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".RemoteMessageFragment">
- <TextView
- android:id="@+id/textView_remote_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="20dp"
- android:text="Waiting ..."
- android:textSize="22sp"
- android:textStyle="bold" />
- <Button
- android:id="@+id/button_send_remote_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="SEND MESSAGE" />
- </LinearLayout>
- // RemoteMessageFragment, lisätään perusrunko MQTT:lle, joka on lähes identtinen WeatherStationFragmentin kanssa
- // yksityiskohdat muutetaan HiveMQ:lle täsmääviksi, ja subscribeToTopicin
- // ja callback -> publish on erilainen (koska eri fragment)
- class RemoteMessageFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentRemoteMessageBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // client-olio, jolla voidaan yhdistää MQTT-brokeriin koodin avulla
- private lateinit var client: Mqtt3AsyncClient
- // apufunktio/metodi jolla yhdistetään sääaseman topiciin
- // JOS yhteys onnistui aiemmin
- fun subscribeToTopic()
- {
- client.subscribeWith()
- .topicFilter(BuildConfig.HIVEMQ_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- }
- .send()
- .whenComplete { subAck, throwable ->
- if (throwable != null) {
- // Handle failure to subscribe
- Log.d("ADVTECH", "Subscribe failed.")
- } else {
- // Handle successful subscription, e.g. logging or incrementing a metric
- Log.d("ADVTECH", "Subscribed!")
- }
- }
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // version 3, IBM Cloud, weather station
- // käytetään tällä kertaa aina samaa client id:tä, ettei ilmaiset
- // client id:t kulu ilmaisessa HiveMQ-palvelussa
- client = MqttClient.builder()
- .useMqttVersion3()
- .sslWithDefaultConfig()
- .identifier("android2023test123")
- .serverHost(BuildConfig.HIVEMQ_BROKER)
- .serverPort(8883)
- .buildAsync()
- // yhdistetään käyttäjätiedoilla (username/password)
- client.connectWith()
- .simpleAuth()
- .username(BuildConfig.HIVEMQ_USERNAME)
- .password(BuildConfig.HIVEMQ_PASSWORD.toByteArray())
- .applySimpleAuth()
- .send()
- .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
- if (throwable != null) {
- Log.d("ADVTECH", "Connection failure.")
- } else {
- // Setup subscribes or start publishing
- subscribeToTopic()
- }
- }
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- // suljetaan MQTT-yhteys mikäli fragment suljetaan
- client.disconnect()
- }
- }
- // Asetetaan vastaanotettu MQTT-viesti käyttöliittymään, esim:
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- activity?.runOnUiThread {
- binding.textViewRemoteMessage.text = result
- }
- }
- // uuden viestin lähettäminen on melko yksinkertaista:
- // tämä koodi onCreateViewin sisälle:
- // tehdään testinappi, joka lähettää satunnaisen viestin samaan topicciin
- binding.buttonSendRemoteMessage.setOnClickListener {
- // jos tulee virhe Randomin kanssa, ota ylhältä importeista
- // java.util.* pois, ja importtaa Kotlinin versio Randomista
- var randomNumber = Random.nextInt(0, 100)
- var stringPayload = "Hello world! " + randomNumber.toString()
- client.publishWith()
- .topic(BuildConfig.HIVEMQ_TOPIC)
- .payload(stringPayload.toByteArray())
- .send()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement