Advertisement
tuomasvaltanen

Untitled

Mar 24th, 2023 (edited)
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.14 KB | None | 0 0
  1. Edistynyt mobiiliohjelmointi, 24.3.2023, B243, AAMULUENTO
  2. ---------------------------------------------------
  3.  
  4. Tehdään tänään oma MQTT-klusteri HiveMQ-palveluun, testataan yhteydet MQTTX:llä, ja ohjelmoidaan sitten Androidiin fragment, joka osaa lähettää ja vastaanottaa tekstidataa.
  5.  
  6. Vaiheet:
  7.  
  8. 1. Tee Harjoitus 4 ohjeen mukaisesti HiveMQ-palveluun oma klusteri, tee käyttäjätunnus, ja
  9. testaa datan liikkuminen (lähetys ja vastaanotto) molempiin suuntiin ohjeen mukaisella topicilla MQTTX-ohjelmalle
  10.  
  11. 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
  12.  
  13. 3. Tee local.properties-tiedostoon tarvittavat muuttujat HiveMQ:ta varten (ei lainausmerkkejä mihinkään arvoon):
  14.  
  15. HIVEMQ_BROKER=oman_klusterin_osoite
  16. HIVEMQ_USERNAME=oman_klusterin_käyttäjänimi
  17. HIVEMQ_PASSWORD=oman_klusterin_salasana
  18. HIVEMQ_TOPIC=koodin_käyttämä_topic
  19.  
  20. 4. Jatketaan tästä vaiheesta yhdessä klo 9:20
  21.  
  22.  
  23. -----------
  24.  
  25. RemoteMessageFragmentin ulkoasu, TextView ja Button, esim.
  26.  
  27. <?xml version="1.0" encoding="utf-8"?>
  28. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  29. xmlns:tools="http://schemas.android.com/tools"
  30. android:layout_width="match_parent"
  31. android:layout_height="match_parent"
  32. android:layout_margin="10dp"
  33. android:orientation="vertical"
  34. tools:context=".RemoteMessageFragment">
  35.  
  36. <TextView
  37. android:id="@+id/textView_remote_message"
  38. android:layout_width="match_parent"
  39. android:layout_height="wrap_content"
  40. android:textSize="22sp"
  41. android:textStyle="bold" />
  42.  
  43. <Button
  44. android:id="@+id/button_send_remote_message"
  45. android:layout_width="match_parent"
  46. android:layout_height="wrap_content"
  47. android:layout_marginTop="10dp"
  48. android:text="Button" />
  49. </LinearLayout>
  50.  
  51. RemoteMessageFragment.kt, viestin vastaanottaminen:
  52.  
  53. class RemoteMessageFragment : Fragment() {
  54. // change this to match your fragment name
  55. private var _binding: FragmentRemoteMessageBinding? = null
  56.  
  57. // This property is only valid between onCreateView and
  58. // onDestroyView.
  59. private val binding get() = _binding!!
  60.  
  61. // HiveMQ MQTT ver 3 -client
  62. private lateinit var client: Mqtt3AsyncClient
  63.  
  64. override fun onCreateView(
  65. inflater: LayoutInflater,
  66. container: ViewGroup?,
  67. savedInstanceState: Bundle?
  68. ): View? {
  69. _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
  70. val root: View = binding.root
  71.  
  72. // version 3, IBM Cloud, weather station
  73. // identifier => lisätään local.propertiesissa olevaan alkuosaan satunnainen teksti
  74. // jotta saadaan uniikki osa myös mukaan (vaadittu IBM Cloudissa)
  75. client = MqttClient.builder()
  76. .useMqttVersion3()
  77. .sslWithDefaultConfig()
  78. .identifier("And23B243TVtest1")
  79. .serverHost(BuildConfig.HIVEMQ_BROKER)
  80. .serverPort(8883)
  81. .buildAsync()
  82.  
  83. client.connectWith()
  84. .simpleAuth()
  85. .username(BuildConfig.HIVEMQ_USERNAME)
  86. .password(BuildConfig.HIVEMQ_PASSWORD.toByteArray())
  87. .applySimpleAuth()
  88. .send()
  89. .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
  90. if (throwable != null) {
  91. Log.d("ADVTECH", "Connection failure.")
  92. Log.d("ADVTECH", throwable.message.toString())
  93. } else {
  94. // Setup subscribes or start publishing
  95. subscribeToTopic()
  96. }
  97. }
  98.  
  99. return root
  100. }
  101.  
  102. // subscribe apufunktio
  103. fun subscribeToTopic()
  104. {
  105. client.subscribeWith()
  106. .topicFilter("test/topic")
  107. .callback { publish ->
  108. // this callback runs everytime your code receives new data payload
  109. var result = String(publish.getPayloadAsBytes())
  110. Log.d("ADVTECH", result)
  111.  
  112. activity?.runOnUiThread{
  113. binding.textViewRemoteMessage.text = result
  114. }
  115.  
  116. }
  117. .send()
  118. .whenComplete { subAck, throwable ->
  119. if (throwable != null) {
  120. // Handle failure to subscribe
  121. Log.d("ADVTECH", "Subscribe failed.")
  122. } else {
  123. // Handle successful subscription, e.g. logging or incrementing a metric
  124. Log.d("ADVTECH", "Subscribed!")
  125. }
  126. }
  127. }
  128.  
  129. override fun onDestroyView() {
  130. super.onDestroyView()
  131. _binding = null
  132.  
  133. // kannattaa myös katkaista MQTT-yhteys kun fragment suljetaan
  134. client.disconnect()
  135. }
  136. }
  137.  
  138. // jos halutaan lähettää dataa napin kautta, esim. jos Buttonin id on button_send_remote_message, voidaan asettaa tämä onCreateViewiin:
  139.  
  140. // kun nappia painetaan, generoidaan satunnainen viesti ja
  141. // lähetetään samaan topiciin. tässä tapauksessa esim. test/topic
  142. binding.buttonSendRemoteMessage.setOnClickListener {
  143. var randomNumber = Random.nextInt(0, 100)
  144. var stringPayload = "Hello world! " + randomNumber.toString()
  145.  
  146. client.publishWith()
  147. .topic(BuildConfig.HIVEMQ_TOPIC)
  148. .payload(stringPayload.toByteArray())
  149. .send()
  150. }
  151.  
  152.  
  153. // Kolmannen osapuolen Custom Viewit:
  154.  
  155. // kokeillaan
  156. https://github.com/ybq/Android-SpinKit
  157.  
  158. // osa kolmannen osapuolen liitännöistä vaatii jitpack.io -repositoryyn yhteyden.
  159.  
  160. Avaa settings.gradle, ja lisää
  161.  
  162. maven { url "https://jitpack.io" }
  163.  
  164. molempiin repositories-kohtaan, eli kaikkinensa:
  165.  
  166. pluginManagement {
  167. repositories {
  168. google()
  169. mavenCentral()
  170. gradlePluginPortal()
  171. maven { url "https://jitpack.io" }
  172. }
  173. }
  174. dependencyResolutionManagement {
  175. repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  176. repositories {
  177. google()
  178. mavenCentral()
  179. maven { url "https://jitpack.io" }
  180. }
  181. }
  182.  
  183. esim fragment_homen ulkoasuun:
  184.  
  185. <com.github.ybq.android.spinkit.SpinKitView
  186. android:id="@+id/spin_kit"
  187. style="@style/SpinKitView.Large.Wave"
  188. android:layout_width="wrap_content"
  189. android:layout_height="wrap_content"
  190. android:layout_gravity="center"
  191. app:SpinKit_Color="@color/purple_200"
  192. app:layout_constraintBottom_toBottomOf="parent"
  193. app:layout_constraintEnd_toEndOf="parent"
  194. app:layout_constraintStart_toStartOf="parent" />
  195.  
  196. // seuraava plugin : https://github.com/anastr/SpeedView
  197.  
  198. // hyödynnetään tätä pluginia sääasema (MQTT) -fragmentissa, muutetaan ulkoasua:
  199.  
  200. <?xml version="1.0" encoding="utf-8"?>
  201. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  202. xmlns:app="http://schemas.android.com/apk/res-auto"
  203. xmlns:tools="http://schemas.android.com/tools"
  204. android:layout_width="match_parent"
  205. android:layout_height="match_parent"
  206. tools:context=".WeatherStationFragment">
  207.  
  208. <!-- TODO: Update blank fragment layout -->
  209. <TextView
  210. android:id="@+id/textView_weather_data"
  211. android:layout_width="match_parent"
  212. android:layout_height="wrap_content"
  213. android:layout_margin="5sp"
  214. android:text="@string/hello_blank_fragment"
  215. android:textSize="24sp"
  216. android:textStyle="bold"
  217. app:layout_constraintEnd_toEndOf="parent"
  218. app:layout_constraintTop_toTopOf="parent" />
  219.  
  220. </androidx.constraintlayout.widget.ConstraintLayout>
  221.  
  222. // säädetään speedviewiä hieman, min ja max arvot välilläe -50 ja 50, ja yksiköksi celsius
  223. // otetaan myös tremble pois, koska se heiluttaa koko ajan arvoa, eikä vastaa oikeaa dataa
  224.  
  225. <com.github.anastr.speedviewlib.SpeedView
  226. android:id="@+id/speedView"
  227. android:layout_width="wrap_content"
  228. android:layout_height="wrap_content"
  229. android:layout_margin="30dp"
  230. app:layout_constraintBottom_toBottomOf="parent"
  231. app:layout_constraintEnd_toEndOf="parent"
  232. app:layout_constraintStart_toStartOf="parent"
  233. app:sv_withTremble="false"
  234. app:sv_minSpeed="-50"
  235. app:sv_maxSpeed="50"
  236. app:sv_unit="℃"
  237. app:layout_constraintTop_toBottomOf="@+id/textView_weather_data" />
  238.  
  239. // nyt voidaan kytkeä sääasemadata speedviewiin MQTT-koodissa, esim.
  240.  
  241.  
  242. try {
  243. var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
  244.  
  245. // haetaan lämpötila WeatherStation-objektin kautta
  246. // haetaan myös ilmanpaine
  247. var temperature = item.d.get1().v.toString()
  248. var pressure = item.d.get2().v.toString()
  249.  
  250. // rakennetaan simppeli teksti ulkoasua varten
  251. var output = "Temp: ${temperature} C\nPressure:${pressure}"
  252.  
  253. // haetaan Float-muotoinen lämpötila speedviewiä varten
  254. var temperatureValue = item.d.get1().v.toFloat()
  255.  
  256. // ajetaan ulkoasuun liittyvät asiat UI-säikeessä
  257. // koska MQTT toimii itsessään taustasäikeessä
  258. // ilman tätä, ohjelma kaatuu
  259. activity?.runOnUiThread(java.lang.Runnable {
  260. binding.textViewWeatherData.text = output
  261. binding.speedView.speedTo(temperatureValue)
  262. })
  263. }
  264.  
  265. // kokeillaan kustomikalenteria, muista myös jitpack lisätä settings.gradleen (ks. aiemmat ohjeet), import:
  266.  
  267. implementation 'com.github.npanigrahy:Custom-Calendar-View:v1.1'
  268.  
  269. Ohjeet (mutta vain Javalle):
  270.  
  271. https://github.com/npanigrahy/Custom-Calendar-View
  272.  
  273. Hae ohjeista XML joka lisätään ulkoasuun (default riittää)
  274.  
  275. Esim. CalendarFragment, onCreateView:
  276.  
  277.  
  278. // haetaan javan peruskalenteriolio
  279. val currentCalendar = Calendar.getInstance(Locale.getDefault())
  280.  
  281. // the binding -object allows you to access views in the layout, textviews etc.
  282. //Show Monday as first date of week
  283. binding.calendarView.setFirstDayOfWeek(Calendar.MONDAY)
  284.  
  285. //Show/hide overflow days of a month
  286. binding.calendarView.setShowOverflowDate(false)
  287.  
  288. //call refreshCalendar to update calendar the view
  289. binding.calendarView.refreshCalendar(currentCalendar)
  290.  
  291. //Handling custom calendar events
  292. binding.calendarView.setCalendarListener(object : CalendarListener {
  293. override fun onDateSelected(date: Date?) {
  294. val df = SimpleDateFormat("dd-MM-yyyy")
  295. Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
  296. }
  297.  
  298. override fun onMonthChanged(date: Date?) {
  299. val df = SimpleDateFormat("MM-yyyy")
  300. Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
  301. }
  302. })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement