Advertisement
tuomasvaltanen

Untitled

Mar 24th, 2023 (edited)
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.15 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 24.3.2023, ILTAPÄIVÄRYHMÄ
  2.  
  3. 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.
  4.  
  5. 1. Tee Harjoitus 4 ohjeen mukaisesti HiveMQ-palveluun oma klusteri, tee käyttäjätunnus, ja
  6. testaa datan liikkuminen (lähetys ja vastaanotto) molempiin suuntiin ohjeen mukaisella topicilla MQTTX-ohjelmalle
  7.  
  8. 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
  9.  
  10. 3. Tee local.properties-tiedostoon tarvittavat muuttujat HiveMQ:ta varten (ei lainausmerkkejä mihinkään arvoon):
  11.  
  12. HIVEMQ_BROKER=oman_klusterin_osoite
  13. HIVEMQ_USERNAME=oman_klusterin_käyttäjänimi
  14. HIVEMQ_PASSWORD=oman_klusterin_salasana
  15. HIVEMQ_TOPIC=koodin_käyttämä_topic
  16.  
  17. 4. Jatketaan tästä vaiheesta yhdessä klo 13:30
  18.  
  19. // uusi fragmentti, RemoteMessageFragment, lisätään päävalikkoon, pohjakoodi:
  20.  
  21. class RemoteMessageFragment : Fragment() {
  22. // change this to match your fragment name
  23. private var _binding: FragmentRemoteMessageBinding? = 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 = FragmentRemoteMessageBinding.inflate(inflater, container, false)
  35. val root: View = binding.root
  36.  
  37.  
  38. return root
  39. }
  40.  
  41. override fun onDestroyView() {
  42. super.onDestroyView()
  43. _binding = null
  44. }
  45. }
  46.  
  47. // lisätään RemoteMessageFragmentin ulkoasuun TextView ja Button,
  48.  
  49. <?xml version="1.0" encoding="utf-8"?>
  50. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  51. xmlns:tools="http://schemas.android.com/tools"
  52. android:layout_width="match_parent"
  53. android:layout_height="match_parent"
  54. android:layout_margin="10dp"
  55. android:orientation="vertical"
  56. tools:context=".RemoteMessageFragment">
  57.  
  58.  
  59. <TextView
  60. android:id="@+id/textView_remote_message"
  61. android:layout_width="match_parent"
  62. android:layout_height="wrap_content"
  63. android:text="Waiting..."
  64. android:textSize="22sp"
  65. android:textStyle="bold" />
  66.  
  67. <Button
  68. android:id="@+id/button_send_remote_message"
  69. android:layout_width="match_parent"
  70. android:layout_height="wrap_content"
  71. android:layout_marginTop="20dp"
  72. android:text="SEND MESSAGE" />
  73. </LinearLayout>
  74.  
  75. // Yhdistetään MQTT:hen omilla HiveMQ-tunnuksilla
  76.  
  77. class RemoteMessageFragment : Fragment() {
  78. // change this to match your fragment name
  79. private var _binding: FragmentRemoteMessageBinding? = null
  80.  
  81. // This property is only valid between onCreateView and
  82. // onDestroyView.
  83. private val binding get() = _binding!!
  84.  
  85. // MQTT -client tarvitaan
  86. private lateinit var client: Mqtt3AsyncClient
  87.  
  88. override fun onCreateView(
  89. inflater: LayoutInflater,
  90. container: ViewGroup?,
  91. savedInstanceState: Bundle?
  92. ): View? {
  93. _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
  94. val root: View = binding.root
  95.  
  96. // version 3, IBM Cloud, weather station
  97. client = MqttClient.builder()
  98. .useMqttVersion3()
  99. .sslWithDefaultConfig()
  100. .identifier("kagjjkadsfhjksdfh784973")
  101. .serverHost(BuildConfig.HIVEMQ_BROKER)
  102. .serverPort(8883)
  103. .buildAsync()
  104.  
  105. client.connectWith()
  106. .simpleAuth()
  107. .username(BuildConfig.HIVEMQ_USERNAME)
  108. .password(BuildConfig.HIVEMQ_PASSWORD.toByteArray())
  109. .applySimpleAuth()
  110. .send()
  111. .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
  112. if (throwable != null) {
  113. Log.d("ADVTECH", "Connection failure.")
  114. } else {
  115. // Setup subscribes or start publishing
  116. subscribeToTopic()
  117. }
  118. }
  119.  
  120. return root
  121. }
  122.  
  123. fun subscribeToTopic()
  124. {
  125. client.subscribeWith()
  126. .topicFilter(BuildConfig.HIVEMQ_TOPIC)
  127. .callback { publish ->
  128. // this callback runs everytime your code receives new data payload
  129. var result = String(publish.getPayloadAsBytes())
  130. Log.d("ADVTECH", result)
  131.  
  132. // laitetaan vastaanotettu data ulkoasuun
  133. activity?.runOnUiThread {
  134. binding.textViewRemoteMessage.text = result
  135. }
  136.  
  137.  
  138. }
  139. .send()
  140. .whenComplete { subAck, throwable ->
  141. if (throwable != null) {
  142. // Handle failure to subscribe
  143. Log.d("ADVTECH", "Subscribe failed.")
  144. } else {
  145. // Handle successful subscription, e.g. logging or incrementing a metric
  146. Log.d("ADVTECH", "Subscribed!")
  147. }
  148. }
  149. }
  150.  
  151. override fun onDestroyView() {
  152. super.onDestroyView()
  153. _binding = null
  154.  
  155. // hyvä tapa sammuttaa MQTT-client kun poistutaan fragmentista
  156. client.disconnect()
  157. }
  158. }
  159.  
  160. // jos halutaan napilla lähettää dataa, onCreateViewiin esim: (koodissa pitää olla button_send_remote_message id:llä Button)
  161.  
  162. // kun nappia painetaa, lähetetään satunnainen hello world -viesti
  163. // topicciin
  164. binding.buttonSendRemoteMessage.setOnClickListener {
  165. var randomNumber = Random.nextInt(0, 100)
  166. var stringPayload = "Hello world! " + randomNumber.toString()
  167.  
  168. client.publishWith()
  169. .topic(BuildConfig.HIVEMQ_TOPIC)
  170. .payload(stringPayload.toByteArray())
  171. .send()
  172. }
  173.  
  174.  
  175. // kolmannen osapuolen komponentit, SpinKit
  176.  
  177. https://github.com/ybq/Android-SpinKit
  178.  
  179. // lisätään importti
  180. implementation 'com.github.ybq:Android-SpinKit:1.4.0'
  181.  
  182. // koska iso osa kolmannen osa puolen komponenteista on jitpack.io -palvelussa, pitää meidän lisätä myös sen osoite
  183.  
  184. settings.gradle:
  185.  
  186. molempiin repositoryihin:
  187.  
  188. maven { url "https://jitpack.io" }
  189.  
  190. Eli esim.
  191.  
  192. pluginManagement {
  193. repositories {
  194. google()
  195. mavenCentral()
  196. gradlePluginPortal()
  197. maven { url "https://jitpack.io" }
  198. }
  199. }
  200. dependencyResolutionManagement {
  201. repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  202. repositories {
  203. google()
  204. mavenCentral()
  205. maven { url "https://jitpack.io" }
  206. }
  207. }
  208.  
  209. // kokeillaan esim home fragmentin ulkoasussa:
  210.  
  211.  
  212. <com.github.ybq.android.spinkit.SpinKitView
  213. android:id="@+id/spin_kit"
  214. style="@style/SpinKitView.Large.Wave"
  215. android:layout_width="wrap_content"
  216. android:layout_height="wrap_content"
  217. android:layout_gravity="center"
  218. app:SpinKit_Color="@color/purple_200"
  219. app:layout_constraintBottom_toBottomOf="parent"
  220. app:layout_constraintEnd_toEndOf="parent"
  221. app:layout_constraintStart_toStartOf="parent"
  222. app:layout_constraintTop_toBottomOf="@+id/text_home" />
  223.  
  224.  
  225. // speedometer, implementation 'com.github.anastr:speedviewlib:1.6.0'
  226. // ohjeet: https://github.com/anastr/SpeedView
  227.  
  228. // WeatherStationFragmentin ulkoasu, otetaan constraintlayout käyttöön jotta saadaan speedview helposti mukaan
  229.  
  230. <?xml version="1.0" encoding="utf-8"?>
  231. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  232. xmlns:app="http://schemas.android.com/apk/res-auto"
  233. xmlns:tools="http://schemas.android.com/tools"
  234. android:layout_width="match_parent"
  235. android:layout_height="match_parent"
  236. tools:context=".WeatherStationFragment">
  237.  
  238. <!-- TODO: Update blank fragment layout -->
  239. <TextView
  240. android:id="@+id/textView_weather_station_temperature"
  241. android:layout_width="match_parent"
  242. android:layout_height="wrap_content"
  243. android:layout_margin="5dp"
  244. android:layout_marginStart="5dp"
  245. android:layout_marginEnd="4dp"
  246. android:text="Waiting data..."
  247. android:textSize="22sp"
  248. android:textStyle="bold"
  249. app:layout_constraintEnd_toEndOf="parent"
  250. app:layout_constraintStart_toStartOf="parent"
  251. app:layout_constraintTop_toTopOf="parent" />
  252.  
  253. </androidx.constraintlayout.widget.ConstraintLayout>
  254.  
  255.  
  256. // mittarin xml:
  257.  
  258. <com.github.anastr.speedviewlib.SpeedView
  259. android:id="@+id/speedView"
  260. android:layout_width="wrap_content"
  261. android:layout_height="wrap_content"
  262. app:layout_constraintBottom_toBottomOf="parent"
  263. app:layout_constraintEnd_toEndOf="parent"
  264. app:layout_constraintStart_toStartOf="parent"
  265. />
  266.  
  267.  
  268. // säädetään parametreja, min ja max ja unitm sekä tremble oius
  269.  
  270. <com.github.anastr.speedviewlib.SpeedView
  271. android:id="@+id/speedView"
  272. android:layout_width="wrap_content"
  273. android:layout_height="wrap_content"
  274. app:sv_withTremble="false"
  275. app:sv_minSpeed="-50"
  276. app:sv_maxSpeed="50"
  277. app:sv_unit="℃"
  278. app:layout_constraintBottom_toBottomOf="parent"
  279. app:layout_constraintEnd_toEndOf="parent"
  280. app:layout_constraintStart_toStartOf="parent"
  281. />
  282.  
  283.  
  284. // kustomikalenteri, linkki:
  285. https://github.com/npanigrahy/Custom-Calendar-View
  286.  
  287. Muista asentaa versio 1.1, 1.0 ei toimi
  288. implementation 'com.github.npanigrahy:Custom-Calendar-View:v1.1'
  289.  
  290. Uusi fragment, CalendarFragment, ulkoasu;
  291.  
  292. <?xml version="1.0" encoding="utf-8"?>
  293. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  294. xmlns:tools="http://schemas.android.com/tools"
  295. android:layout_width="match_parent"
  296. android:layout_height="match_parent"
  297. tools:context=".CalendarFragment">
  298.  
  299. <com.stacktips.view.CustomCalendarView
  300. android:id="@+id/calendar_view"
  301. android:layout_width="match_parent"
  302. android:layout_height="wrap_content"
  303. android:background="#ffffff">
  304. </com.stacktips.view.CustomCalendarView>
  305.  
  306. </FrameLayout>
  307.  
  308. // CalendarFragment.kt:
  309.  
  310. class CalendarFragment : Fragment() {
  311. // change this to match your fragment name
  312. private var _binding: FragmentCalendarBinding? = null
  313.  
  314. // This property is only valid between onCreateView and
  315. // onDestroyView.
  316. private val binding get() = _binding!!
  317.  
  318. override fun onCreateView(
  319. inflater: LayoutInflater,
  320. container: ViewGroup?,
  321. savedInstanceState: Bundle?
  322. ): View? {
  323. _binding = FragmentCalendarBinding.inflate(inflater, container, false)
  324. val root: View = binding.root
  325.  
  326. //Initialize calendar with date
  327. val currentCalendar: Calendar = Calendar.getInstance(Locale.getDefault())
  328.  
  329. //Show Monday as first date of week
  330. binding.calendarView.setFirstDayOfWeek(Calendar.MONDAY)
  331.  
  332. //Show/hide overflow days of a month
  333. binding.calendarView.setShowOverflowDate(false)
  334.  
  335. //call refreshCalendar to update calendar the view
  336. binding.calendarView.refreshCalendar(currentCalendar)
  337.  
  338. //Handling custom calendar events
  339. binding.calendarView.setCalendarListener(object : CalendarListener {
  340. override fun onDateSelected(date: Date?) {
  341. val df = SimpleDateFormat("dd-MM-yyyy")
  342. Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
  343. }
  344.  
  345. override fun onMonthChanged(date: Date?) {
  346. val df = SimpleDateFormat("MM-yyyy")
  347. Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
  348. }
  349. })
  350.  
  351. // the binding -object allows you to access views in the layout, textviews etc.
  352.  
  353. return root
  354. }
  355.  
  356. override fun onDestroyView() {
  357. super.onDestroyView()
  358. _binding = null
  359. }
  360. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement