Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Edistynyt mobiiliohjelmointi, 14.3.2023
- ---------------------------------------
- Aiemmalla luennolla luotiin valmiiksi FeedbackReadFragment ja FeedbackSendFragment.
- Nähtävästi Directusin omat käyttökustannukset ovat nousseet niin suuriksi, että ilmaisprojekteja ei tällä hetkellä voi enää tehdä. Ks.
- https://directus.io/blog/cloud-update/
- Tämän vuoksi Directus Cloudin tilalle katsotaan jokin toinen samankaltainen vaihtoehto, ja tätä tehtävää jatketaan jälleen ensi luennolla.
- Tämän luennon pääaiheena käydään etukäteen Harjoitus 4, eli MQTT.
- Voit kokeilla MQTT-protokollan käyttämistä MQTTX -ohjelman avulla:
- https://mqttx.app/
- Tätä MQTT-palvelinta (eli Brokeria) voidaan testata:
- https://test.mosquitto.org/
- Yhdistä näillä tiedoilla:
- Broker host: test.mosquitto.org/
- Port: 8885
- Ei käyttäjänimeä tai salasanaa
- Client ID täytyy olla täysin uniikki (mutta se voi olla mitä vain). Jos kaksi laitetta yhdistää samalla Client ID:llä, vanhempi yhteys tippuu pois linjoilta.
- Kokeile tämän jälkeen subscribettää topiciin test/lapinamk
- Kokeile tämän jälkeen lähettää (eli publish) viesti topiciin test/lapinamk, plain text riittää. (työkalu MQTTX:n alaosassa, ks. ohjeet Harjoitus 4).
- Voit tämän jälkeen kokeilla myös yhdistää Lapin AMK / TEQUn sääasemia (ks. Harjoitus 4). Huomaa että Ounasvaaran data tulee siistissä muodossa, mutta Ruotsin data tulee optimoituna pienempänä datana, jossa jokainen kentän nimi on pelkkä numero. (ks. Moodlessa sääaseman selitteet mitä mikäkin numero tarkoittaa).
- Harjoituksen vuoksi teemme harjoituksen 4 Ruotsin datalla, koska se on vaikeampi käyttää.
- Esimerkkidata Ruotsin sääasemasta:
- {"d":{"1":{"v":-7.5},"2":{"v":962.2},"3":{"v":100},"4":{"v":-7.5},"7":{"v":70},"8":{"v":0.08},"9":{"v":156},"10":{"v":1},"11":{"v":4.9}},"ts":"2023-03-14T11:20:29.342Z"}
- json2kt.com ei toimi tällä datalla oikein, koska kenttien nimet ovat numeroita. Tämän vuoksi luokan nimeksi tulee esim.
- data class 1, mikä on syntaksivirhe, eikä toimi ollenkaan.
- Voimme käyttää tätä sen sijaan (ks. ohje Harjoitus 4:ssä):
- https://www.jsonschema2pojo.org/
- JsonSchema2Pojo on vanhempi työkalu, joka käyttää Javaa. Voimme kuitenkin käyttää Kotlin -projektissa Java-tiedostoja.
- Muista asentaa myös tämä plugin, jotta Java-luokat toimivat oikein:
- implementation 'javax.annotation:javax.annotation-api:1.3.2'
- jsonschema2pojon myötä latauslinkistä pitäisi tulla 11 tiedostoa kaikkiaan, jossa kaikki numerot on merkitty alkavalla alaviivalla (minkä vuoksi ne taas toimii).
- // WeatherStationFragment, versio 1, raakadata konsoliin
- 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!!
- // muuttujat BuildConfigiin myöhemmin
- // this could be in BuildConfig (local.properties -file) too
- // e.g. var MQTT_URL = BuildConfig.MQTT_URL
- var MQTT_URL = "URL TÄHÄN"
- var MQTT_TOPIC = "TOPIC TÄHÄN"
- var MQTT_USERNAME = "username tähän"
- var MQTT_PASSWORD = "salasana tähän"
- // var MQTT_CLIENT_ID = BuildConfig.MQTT_CLIENT_ID + UUID.randomUUID().toString()
- var MQTT_CLIENT_ID = "client id:n alkuosa tähän" + UUID.randomUUID().toString()
- private lateinit var client: Mqtt3AsyncClient
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentWeatherStationBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // version 3, IBM Cloud, weather station
- client = MqttClient.builder()
- .useMqttVersion3()
- .sslWithDefaultConfig()
- .identifier(MQTT_CLIENT_ID)
- .serverHost(MQTT_URL)
- .serverPort(8883)
- .buildAsync()
- client.connectWith()
- .simpleAuth()
- .username(MQTT_USERNAME)
- .password(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()
- }
- }
- return root
- }
- fun subscribeToTopic()
- {
- client.subscribeWith()
- .topicFilter(MQTT_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- // laitetaan raakadata TextViewiin, ei toimi suoraan
- // koska tämä callback ei pääse käyttöliittymään käsiksi (eri thread)
- //binding.textViewWeatherStationTemperature.text = 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!")
- }
- }
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- // hyvä tapa sammuttaa MQTT-client kun poistutaan fragmentista
- client.disconnect()
- }
- }
- // subscribeToTopic() -> versio 2, päivitetään raakadata ulkoasuun
- fun subscribeToTopic()
- {
- client.subscribeWith()
- .topicFilter(MQTT_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- // laitetaan raakadata TextViewiin, ei toimi suoraan
- // koska tämä callback ei pääse käyttöliittymään käsiksi (eri thread)
- // binding.textViewWeatherStationTemperature.text = result
- // ajetaan binding-layeria koskevat asia UI-threadissa erikseen
- activity?.runOnUiThread(java.lang.Runnable {
- binding.textViewWeatherStationTemperature.text = 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!")
- }
- }
- }
- // versio 3, subscribeToTopic -> GSON + try/catch ettei koodi kaadu kun tulee diagnostiikkaa
- fun subscribeToTopic()
- {
- // alustetaan GSON
- val gson = GsonBuilder().setPrettyPrinting().create()
- client.subscribeWith()
- .topicFilter(MQTT_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- // laitetaan raakadata TextViewiin, ei toimi suoraan
- // koska tämä callback ei pääse käyttöliittymään käsiksi (eri thread)
- // binding.textViewWeatherStationTemperature.text = result
- // käytetään try-catch-rakennetta, ettei koodi kaadu
- // kun sääasemalta tulee diagnostiikkadata (joka ei sovellus WeatherStation-pohjaan)
- try {
- var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
- var text = item.d.get1().v.toString() + " C"
- text += "\n"
- text += item.d.get2().v.toString() + " (pressure)"
- // ajetaan binding-layeria koskevat asia UI-threadissa erikseen
- activity?.runOnUiThread(java.lang.Runnable {
- binding.textViewWeatherStationTemperature.text = text
- })
- }
- catch (e : Exception) {
- Log.d("ADVTECH", e.message.toString())
- }
- }
- .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 tulee tämäntyyppinen virhe:
- java.lang.NumberFormatException: Expected an int but was 98.4 at line 1 column 51 path $.d.3.v
- tarkoittaa se sitä että luokassa _3.java käytetään int -tyyppiä muuttujalle v, mutta data sattuikin olemaan desimaaliluku.
- Muuta _3.java luokkaa esim näin:
- private double v;
- public double getV() {
- return v;
- }
- public void setV(double v) {
- this.v = v;
- }
- public _3 withV(double v) {
- this.v = v;
- return this;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement