Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 31.3.2023
- MQTT X:
- Kokeillaan uniikilla Client id:llä (keksi itse)
- test.mosquitto.org
- portti 8886
- ja SSL päälle
- // kokeillaan myös Ounasvaaran ja Ruotsin sääasemat
- //, että client id:n alkuosa pitää olla IBM:n -palvelun takia aina sama, ja loppuosa on vain uniikki
- // esimerkki Ruotsin datasta:
- {"d":{"1":{"v":-4.1},"2":{"v":978.8},"3":{"v":100},"4":{"v":-4.1},"7":{"v":0},"8":{"v":0},"9":{"v":177},"10":{"v":1},"11":{"v":7.7}},"ts":"2023-03-31T05:55:53.019Z"}
- Huom: kaikki kentät ovat numeroita, mikä on haastavaa koodin näkökulmasta. Numeroiden selitteet löytyvät Moodlesta.
- TEHDÄÄN UUSI FRAGMENT mobile_navigation AVULLA: WeatherStationFragment, esim:
- class WeatherStationFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentWeatherStationBinding? = 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 = FragmentWeatherStationBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // the binding -object allows you to access views in the layout, textviews etc.
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // käytetään jsonschema2pojo.orgia luokkien tuottamiseen
- // Class name = WeatherStation, Package, omasta projektista otetaan. jos paketti on esim com.example.example, ja tarkoitus on kopioida tiedostot datatypes-kansiossa olevaan weatherstation -kansioon (tee weatherstation -kansio mikäli puuttuu), silloin paketti on:
- com.example.example.datatypes.weatherstation
- Muilta osin ks. Harjoitus 4 miten jsonschema2pojoa käytetään.
- Muista myös tämä import että Generated-error poistuu:
- implementation 'javax.annotation:javax.annotation-api:1.3.2'
- // HIVEMQ-pluginin käyttäminen, import:
- implementation("com.hivemq:hivemq-mqtt-client-shaded:1.3.0")
- // laitetaan MQTT-yhdistämistiedot local.properties -tiedostoon:
- MQTT_BROKER=osoite
- MQTT_USERNAME=käyttäjänimi
- MQTT_PASSWORD=salasana
- MQTT_TOPIC=sääaseman topic
- MQTT_CLIENT_ID=ibm cloudin alkuosa
- Muista käyttää projektia päällä emulaattorissa, jotta BuildConfig päivittyy.
- Tämän jälkeen voit hakea muuttujia BuildConfigin kautta, esim. BuildConfig.MQTT_BROKER
- WeatherStationFragment.kt:
- Lisätään luokkamuuttujiksi:
- // BuildConfigin kautta haettavat muuttujat ovat local.propertiesissa
- // jos et voi käyttää local.propertiesia, kirjoita MQTT_URL-muuttujaan arvo suoraan
- var MQTT_URL = BuildConfig.MQTT_BROKER
- private lateinit var client: Mqtt3AsyncClient
- // laitetaan myös onDestroyViewiin disconnect, jotta MQTT-yhteys ei jää päälle jos fragmentia vaihdetaan
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- client.disconnect()
- }
- onCreateViewissä: yhdistetään MQTT-palveluun:
- // huomaa, BuildConfig.MQTT_CLIENT_ID sisältää vain client id:n alkuosan
- // koodi tällä hetkellä generoi randomin hännän, jotta varmasti on uniikki client id
- // version 3, IBM Cloud, weather station
- client = MqttClient.builder()
- .useMqttVersion3()
- .sslWithDefaultConfig()
- .identifier(BuildConfig.MQTT_CLIENT_ID + UUID.randomUUID().toString())
- .serverHost(BuildConfig.MQTT_BROKER)
- .serverPort(8883)
- .buildAsync()
- client.connectWith()
- .simpleAuth()
- .username(BuildConfig.MQTT_USERNAME)
- .password(BuildConfig.MQTT_PASSWORD.toByteArray())
- .applySimpleAuth()
- .send()
- .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
- if (throwable != null) {
- Log.d("ADVTECH", "Connection failure.")
- } else {
- // Setup subscribes or start publishing
- subscribeToTopic()
- }
- }
- myöhemmin tarvittava apufunktio, eli subscribeToTopic():
- fun subscribeToTopic()
- {
- val gson = GsonBuilder().setPrettyPrinting().create()
- client.subscribeWith()
- .topicFilter(BuildConfig.MQTT_TOPIC)
- .callback { publish ->
- // sääasema-dataa tuli, tulostetaan raakadata Logitukseen
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- }
- .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!")
- }
- }
- }
- // GSONin käyttäminen subscribeToTopicissa:
- val gson = GsonBuilder().setPrettyPrinting().create()
- client.subscribeWith()
- .topicFilter(BuildConfig.MQTT_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- // tämä todennäköisesti tuottaa virheitä johtuen mm. datan muodosta, ks. erroreita
- var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
- Log.d("ADVTECH", item.d.get1().v.toString() + "C")
- }
- .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!")
- }
- }
- Jos GSON-koodi antaa virheen tähän tyyliin:
- Caused by: java.lang.NumberFormatException: Expected an int but was 93.2 at line 1 column 49 path $.d.3.v
- Tarkoittaa tämä sitä, että tässä tapauksessa luokassa _3.java, on käytetty int, mutta pitäisi olla double. Muuta kaikkiin int-muuttujiin tyypiksi double, niin se korjaantuu. Tämä ongelma voi tulla muissakin numeroluokissa.
- // muokataan WeatherStationFragmentin ulkoasua, jotta TextViewillä on id:
- <?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">
- <!-- TODO: Update blank fragment layout -->
- <TextView
- android:id="@+id/textView_weatherstation_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Waiting for data..."
- android:textColor="#2AA197"
- android:textSize="28sp"
- android:textStyle="bold" />
- </FrameLayout>
- // säädetään vielä lisää muuttujia tulostukseen, huomaa runOnUiThread-ratkaisu:
- try {
- var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
- Log.d("ADVTECH", item.d.get1().v.toString() + "C")
- // haetaan tiedot muuttujiin
- var temperature = item.d.get1().v
- var pressure = item.d.get2().v
- var humidity = item.d.get3().v
- // yhdistetään muuttujat yhdeksi tekstiksi
- var text = "Temperature: ${temperature}C \nPressure: ${pressure} bar\nHumidity: ${humidity}%\n\n"
- text += item.ts.toString()
- // varmistetaan tällä se, että binding-layeria käsitellään varmasti UI-threadista
- // joissain tapauksissa MQTT-koodi ajetaan tausta-threadissa, jolloin binding-layerin
- // käyttäminen voi tiltata
- activity?.runOnUiThread {
- // asetetaan tekstimuuttuja TextViewiin, joka on käyttöliittymässä
- binding.textViewWeatherstationText.text = text
- }
- }
- catch(e : Exception) {
- Log.d("ADVTECH", e.message.toString())
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement