Advertisement
tuomasvaltanen

Untitled

Mar 31st, 2023 (edited)
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.68 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 31.3.2023
  2.  
  3. MQTT X:
  4.  
  5. Kokeillaan uniikilla Client id:llä (keksi itse)
  6. test.mosquitto.org
  7. portti 8886
  8. ja SSL päälle
  9.  
  10. // kokeillaan myös Ounasvaaran ja Ruotsin sääasemat
  11. //, että client id:n alkuosa pitää olla IBM:n -palvelun takia aina sama, ja loppuosa on vain uniikki
  12.  
  13.  
  14. // esimerkki Ruotsin datasta:
  15. {"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"}
  16.  
  17. Huom: kaikki kentät ovat numeroita, mikä on haastavaa koodin näkökulmasta. Numeroiden selitteet löytyvät Moodlesta.
  18.  
  19. TEHDÄÄN UUSI FRAGMENT mobile_navigation AVULLA: WeatherStationFragment, esim:
  20.  
  21. class WeatherStationFragment : Fragment() {
  22. // change this to match your fragment name
  23. private var _binding: FragmentWeatherStationBinding? = null
  24.  
  25. // This property is only valid between onCreateView and
  26. // onDestroyView.
  27. private val binding get() = _binding!!
  28.  
  29. override fun onCreateView(
  30. inflater: LayoutInflater,
  31. container: ViewGroup?,
  32. savedInstanceState: Bundle?
  33. ): View? {
  34. _binding = FragmentWeatherStationBinding.inflate(inflater, container, false)
  35. val root: View = binding.root
  36.  
  37. // the binding -object allows you to access views in the layout, textviews etc.
  38.  
  39. return root
  40. }
  41.  
  42. override fun onDestroyView() {
  43. super.onDestroyView()
  44. _binding = null
  45. }
  46. }
  47.  
  48. // käytetään jsonschema2pojo.orgia luokkien tuottamiseen
  49. // 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:
  50.  
  51. com.example.example.datatypes.weatherstation
  52.  
  53. Muilta osin ks. Harjoitus 4 miten jsonschema2pojoa käytetään.
  54.  
  55. Muista myös tämä import että Generated-error poistuu:
  56. implementation 'javax.annotation:javax.annotation-api:1.3.2'
  57.  
  58. // HIVEMQ-pluginin käyttäminen, import:
  59.  
  60. implementation("com.hivemq:hivemq-mqtt-client-shaded:1.3.0")
  61.  
  62. // laitetaan MQTT-yhdistämistiedot local.properties -tiedostoon:
  63.  
  64. MQTT_BROKER=osoite
  65. MQTT_USERNAME=käyttäjänimi
  66. MQTT_PASSWORD=salasana
  67. MQTT_TOPIC=sääaseman topic
  68. MQTT_CLIENT_ID=ibm cloudin alkuosa
  69.  
  70. Muista käyttää projektia päällä emulaattorissa, jotta BuildConfig päivittyy.
  71.  
  72. Tämän jälkeen voit hakea muuttujia BuildConfigin kautta, esim. BuildConfig.MQTT_BROKER
  73.  
  74.  
  75. WeatherStationFragment.kt:
  76.  
  77. Lisätään luokkamuuttujiksi:
  78. // BuildConfigin kautta haettavat muuttujat ovat local.propertiesissa
  79. // jos et voi käyttää local.propertiesia, kirjoita MQTT_URL-muuttujaan arvo suoraan
  80. var MQTT_URL = BuildConfig.MQTT_BROKER
  81. private lateinit var client: Mqtt3AsyncClient
  82.  
  83. // laitetaan myös onDestroyViewiin disconnect, jotta MQTT-yhteys ei jää päälle jos fragmentia vaihdetaan
  84. override fun onDestroyView() {
  85. super.onDestroyView()
  86. _binding = null
  87. client.disconnect()
  88. }
  89.  
  90. onCreateViewissä: yhdistetään MQTT-palveluun:
  91.  
  92. // huomaa, BuildConfig.MQTT_CLIENT_ID sisältää vain client id:n alkuosan
  93. // koodi tällä hetkellä generoi randomin hännän, jotta varmasti on uniikki client id
  94.  
  95. // version 3, IBM Cloud, weather station
  96. client = MqttClient.builder()
  97. .useMqttVersion3()
  98. .sslWithDefaultConfig()
  99. .identifier(BuildConfig.MQTT_CLIENT_ID + UUID.randomUUID().toString())
  100. .serverHost(BuildConfig.MQTT_BROKER)
  101. .serverPort(8883)
  102. .buildAsync()
  103.  
  104. client.connectWith()
  105. .simpleAuth()
  106. .username(BuildConfig.MQTT_USERNAME)
  107. .password(BuildConfig.MQTT_PASSWORD.toByteArray())
  108. .applySimpleAuth()
  109. .send()
  110. .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
  111. if (throwable != null) {
  112. Log.d("ADVTECH", "Connection failure.")
  113. } else {
  114. // Setup subscribes or start publishing
  115. subscribeToTopic()
  116. }
  117. }
  118.  
  119.  
  120. myöhemmin tarvittava apufunktio, eli subscribeToTopic():
  121.  
  122. fun subscribeToTopic()
  123. {
  124. val gson = GsonBuilder().setPrettyPrinting().create()
  125.  
  126. client.subscribeWith()
  127. .topicFilter(BuildConfig.MQTT_TOPIC)
  128. .callback { publish ->
  129.  
  130. // sääasema-dataa tuli, tulostetaan raakadata Logitukseen
  131. var result = String(publish.getPayloadAsBytes())
  132. Log.d("ADVTECH", result)
  133.  
  134. }
  135. .send()
  136. .whenComplete { subAck, throwable ->
  137. if (throwable != null) {
  138. // Handle failure to subscribe
  139. Log.d("ADVTECH", "Subscribe failed.")
  140. } else {
  141. // Handle successful subscription, e.g. logging or incrementing a metric
  142. Log.d("ADVTECH", "Subscribed!")
  143. }
  144. }
  145. }
  146.  
  147. // GSONin käyttäminen subscribeToTopicissa:
  148.  
  149. val gson = GsonBuilder().setPrettyPrinting().create()
  150.  
  151. client.subscribeWith()
  152. .topicFilter(BuildConfig.MQTT_TOPIC)
  153. .callback { publish ->
  154.  
  155. // this callback runs everytime your code receives new data payload
  156. var result = String(publish.getPayloadAsBytes())
  157. Log.d("ADVTECH", result)
  158.  
  159. // tämä todennäköisesti tuottaa virheitä johtuen mm. datan muodosta, ks. erroreita
  160. var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
  161. Log.d("ADVTECH", item.d.get1().v.toString() + "C")
  162.  
  163. }
  164. .send()
  165. .whenComplete { subAck, throwable ->
  166. if (throwable != null) {
  167. // Handle failure to subscribe
  168. Log.d("ADVTECH", "Subscribe failed.")
  169. } else {
  170. // Handle successful subscription, e.g. logging or incrementing a metric
  171. Log.d("ADVTECH", "Subscribed!")
  172. }
  173. }
  174.  
  175. Jos GSON-koodi antaa virheen tähän tyyliin:
  176.  
  177. Caused by: java.lang.NumberFormatException: Expected an int but was 93.2 at line 1 column 49 path $.d.3.v
  178.  
  179. 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.
  180.  
  181. // muokataan WeatherStationFragmentin ulkoasua, jotta TextViewillä on id:
  182.  
  183. <?xml version="1.0" encoding="utf-8"?>
  184. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  185. xmlns:tools="http://schemas.android.com/tools"
  186. android:layout_width="match_parent"
  187. android:layout_height="match_parent"
  188. tools:context=".WeatherStationFragment">
  189.  
  190. <!-- TODO: Update blank fragment layout -->
  191. <TextView
  192.  
  193. android:id="@+id/textView_weatherstation_text"
  194. android:layout_width="match_parent"
  195. android:layout_height="wrap_content"
  196. android:layout_margin="10dp"
  197. android:text="Waiting for data..."
  198. android:textColor="#2AA197"
  199. android:textSize="28sp"
  200. android:textStyle="bold" />
  201.  
  202. </FrameLayout>
  203.  
  204. // säädetään vielä lisää muuttujia tulostukseen, huomaa runOnUiThread-ratkaisu:
  205.  
  206. try {
  207. var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
  208. Log.d("ADVTECH", item.d.get1().v.toString() + "C")
  209.  
  210. // haetaan tiedot muuttujiin
  211. var temperature = item.d.get1().v
  212. var pressure = item.d.get2().v
  213. var humidity = item.d.get3().v
  214.  
  215. // yhdistetään muuttujat yhdeksi tekstiksi
  216. var text = "Temperature: ${temperature}C \nPressure: ${pressure} bar\nHumidity: ${humidity}%\n\n"
  217. text += item.ts.toString()
  218.  
  219. // varmistetaan tällä se, että binding-layeria käsitellään varmasti UI-threadista
  220. // joissain tapauksissa MQTT-koodi ajetaan tausta-threadissa, jolloin binding-layerin
  221. // käyttäminen voi tiltata
  222. activity?.runOnUiThread {
  223. // asetetaan tekstimuuttuja TextViewiin, joka on käyttöliittymässä
  224. binding.textViewWeatherstationText.text = text
  225. }
  226.  
  227.  
  228. }
  229. catch(e : Exception) {
  230. Log.d("ADVTECH", e.message.toString())
  231. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement