Advertisement
tuomasvaltanen

Untitled

Apr 24th, 2023 (edited)
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.42 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 24.4.2023
  2.  
  3. Kokeillaan MQTTX:llä julkista MQTT brokeria:
  4.  
  5. https://test.mosquitto.org/
  6.  
  7. Tehdään uusi Connection MQTT X:llä, seuraavilla tiedoilla:
  8.  
  9. Name: mikä vain itse haluat, lähinnä itseäsi varten että tiedät mistä yhteydestä on kyse
  10. Client ID: tämän tulee olla kaikilla käyttäjillä uniikki teksti (esim. 98af7sd98fyhw4ui5t79), koska jos kaksi laitetta yhdistää samalla client id:llä, vanhempi yhteys tippuu pois linjoilta
  11. Host: test.mosquitto.org
  12. Port: 8886
  13.  
  14. SSL/TLS päälle, SSL Secure päällä, ja CA signed server päällä
  15.  
  16. Yhdistetään luennolla topiciin: test/lapinamk
  17.  
  18. // Kokeillaan IBM Cloud / TEQU -sääasemaa, MQTT X:n uusi Connection:
  19.  
  20. Name: mikä vain, esim. WeatherStationTest
  21. Client ID: alkuosa on aina (ks. ohjeesta alkuosa) ---> a:xxxxxx: ja tähän perään oma uniikki osa, eli esim
  22.  
  23. a:xxxxxx:asgf9d87549hrajh
  24.  
  25. Host: ks. Harjoitus 4 ohje, broker address
  26. Username: ks. Harjoitus 4 ohje, API-key / username
  27. Password: ks. Harjoitus 4 ohje, Authentication token / password
  28.  
  29. SSL/TLS päälle, SSL Secure päälle, CA signed server päälle
  30.  
  31. topic:
  32.  
  33. ks. ohje, kokeile ensin Ruotsin dataa (selkeää JSONia), pitäisi tulla seuraavanlaista dataa:
  34.  
  35. {"d":{"temperature":{"v":6.6},"pressure":{"v":1006.9},"relative_humidity":{"v":38.4},"dewpoint":{"v":-8.4},"wind_speed":{"v":2},"wind_direction":{"v":91},"rain_type":{"v":0},"rain_intensity":{"v":0},"global_radiation":{"v":397},"uv_index":{"v":2},"brightness":{"v":13.9},"latitude":{"v":65.56221605},"longitude":{"v":22.099477417},"altitude":{"v":17.9}},"ts":"2023-04-24T14:54:44.410Z"}
  36.  
  37. ... ja sen jälkeen Ounasvaaran dataa, josta pitäisi tulla haastavampaa dataa (huom: kaikki kentät ovat nyt vain numeroita):
  38.  
  39. {"d":{"1":{"v":6.8},"2":{"v":1006.9},"3":{"v":37.8},"4":{"v":-8.5},"5":{"v":0.6},"6":{"v":73},"7":{"v":0},"8":{"v":0},"9":{"v":403},"10":{"v":2},"11":{"v":13.7}},"ts":"2023-04-24T14:59:05.640Z"}
  40.  
  41. // Ounasvaaran dataa ei voi käyttää json2kt.comissa, koska se yrittää tehdä luokkia, joiden nimenä on pelkkä numero (esim. data class 1). tämä ei ole syntaksin näkökulmasta oikeanlaista koodia, ja tällaiset luokat eivät käytännössä toimi.
  42.  
  43. // käytetään tämän sijasta työkalua:
  44. https://www.jsonschema2pojo.org/
  45.  
  46. // ks. ohje tai luentovideo miten työkalua käytetään
  47.  
  48. // tehdään uusi kansio (package) Android-projektiin datatypes-kansion alle -> weatherstation
  49.  
  50. // kopioi työkalusta tulevat Java-tiedostot juuri tehtyyn weatherstation -kansioon.
  51.  
  52. // tarkista että paketti on varmasti oikein työkalussa
  53.  
  54. // eli jos projektisi paketti on com.example.testi2023, ja siellä on datatypes -kansio jossa on weatherstation -kansio, paketti on silloin:
  55.  
  56. com.example.testi2023.datatypes.weatherstation
  57.  
  58. // lisää seuraava import build.gradle / moduleen:
  59.  
  60. implementation 'javax.annotation:javax.annotation-api:1.3.2'
  61.  
  62. Tämän jälkeen @Generated-virhe poistuu tiedostoista.
  63.  
  64. // tehdään uusi Fragment (mobile_navigationin kautta), lisätään se päävalikkoon ja otetaan binding-layer käyttöön, esim:
  65.  
  66. WeatherStationFragment.kt:
  67.  
  68. class WeatherStationFragment : Fragment() {
  69. private var _binding: FragmentWeatherStationBinding? = null
  70. // This property is only valid between onCreateView and
  71. // onDestroyView.
  72. private val binding get() = _binding!!
  73. override fun onCreateView(
  74. inflater: LayoutInflater,
  75. container: ViewGroup?,
  76. savedInstanceState: Bundle?
  77. ): View? {
  78. _binding = FragmentWeatherStationBinding.inflate(inflater, container, false)
  79. val root: View = binding.root
  80.  
  81.  
  82. return root
  83. }
  84. override fun onDestroyView() {
  85. super.onDestroyView()
  86. _binding = null
  87. }
  88. }
  89.  
  90. // lisätään HiveMQ-plugin projektiin, build.gradle / module:
  91.  
  92. implementation("com.hivemq:hivemq-mqtt-client-shaded:1.3.0")
  93.  
  94. // lisätään local.propertiesiin MQTT-muuttujat, ja sitten käynnistetään projekti, jotta saadaan BuildConfig päivitettyä:
  95.  
  96. MQTT_BROKER=OSOITETÄHÄNOHJEISTA
  97. MQTT_CLIENT_ID=CLIENT_IDN_ALKUOSA_TOISEEN_KAKSOISPISTEESEEN_ASTI
  98. MQTT_USERNAME=KSOHJEISTA
  99. MQTT_PASSWORD=OHJEISTA
  100. MQTT_TOPIC=OUNASVAARANLAITETOPIC
  101.  
  102. // kun kaikki Moodlen esimerkit kytketään samaksi koodiksi:
  103.  
  104. class WeatherStationFragment : Fragment() {
  105. private var _binding: FragmentWeatherStationBinding? = null
  106. // This property is only valid between onCreateView and
  107. // onDestroyView.
  108.  
  109. // remember to update your local.properties with values of the MQTT connection
  110.  
  111. // client-olio, jolla voidaan yhdistää MQTT-brokeriin koodin avulla
  112. private lateinit var client: Mqtt3AsyncClient
  113.  
  114. // apufunktio/metodi jolla yhdistetään sääaseman topiciin
  115. // JOS yhteys onnistui aiemmin
  116. fun subscribeToTopic()
  117. {
  118. client.subscribeWith()
  119. .topicFilter(BuildConfig.MQTT_TOPIC)
  120. .callback { publish ->
  121.  
  122. // this callback runs everytime your code receives new data payload
  123. // muutetaan raakadata tekstiksi (tässä tapauksessa JSONia)
  124. var result = String(publish.getPayloadAsBytes())
  125. Log.d("ADVTECH", result)
  126.  
  127. }
  128. .send()
  129. .whenComplete { subAck, throwable ->
  130. if (throwable != null) {
  131. // Handle failure to subscribe
  132. Log.d("ADVTECH", "Subscribe failed.")
  133. } else {
  134. // Handle successful subscription, e.g. logging or incrementing a metric
  135. Log.d("ADVTECH", "Subscribed!")
  136. }
  137. }
  138. }
  139.  
  140.  
  141. private val binding get() = _binding!!
  142. override fun onCreateView(
  143. inflater: LayoutInflater,
  144. container: ViewGroup?,
  145. savedInstanceState: Bundle?
  146. ): View? {
  147. _binding = FragmentWeatherStationBinding.inflate(inflater, container, false)
  148. val root: View = binding.root
  149.  
  150. // version 3, IBM Cloud, weather station
  151. // Huomaa identifier eli Client ID => vain alkuosa toiseen kaksoispisteeseen
  152. // laitetaan local.propertiesiin, ja satunnainen tekstihäntä liitetään
  153. // perään UUID-kirjaston avulla
  154. client = MqttClient.builder()
  155. .useMqttVersion3()
  156. .sslWithDefaultConfig()
  157. .identifier(BuildConfig.MQTT_CLIENT_ID + UUID.randomUUID().toString())
  158. .serverHost(BuildConfig.MQTT_BROKER)
  159. .serverPort(8883)
  160. .buildAsync()
  161.  
  162. // yhdistetään käyttäjätiedoilla (username/password)
  163. client.connectWith()
  164. .simpleAuth()
  165. .username(BuildConfig.MQTT_USERNAME)
  166. .password(BuildConfig.MQTT_PASSWORD.toByteArray())
  167. .applySimpleAuth()
  168. .send()
  169. .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
  170. if (throwable != null) {
  171. Log.d("ADVTECH", "Connection failure.")
  172. } else {
  173. // Setup subscribes or start publishing
  174. subscribeToTopic()
  175. }
  176. }
  177.  
  178. return root
  179. }
  180.  
  181. override fun onDestroyView() {
  182. super.onDestroyView()
  183. _binding = null
  184.  
  185. // suljetaan MQTT-yhteys mikäli fragment suljetaan
  186. client.disconnect()
  187. }
  188. }
  189.  
  190.  
  191. kokeillaan käyttää hieman GSONia:
  192.  
  193. fun subscribeToTopic()
  194. {
  195. // alustetaan GSON
  196. val gson = GsonBuilder().setPrettyPrinting().create()
  197.  
  198. client.subscribeWith()
  199. .topicFilter(BuildConfig.MQTT_TOPIC)
  200. .callback { publish ->
  201.  
  202. // this callback runs everytime your code receives new data payload
  203. // muutetaan raakadata tekstiksi (tässä tapauksessa JSONia)
  204. var result = String(publish.getPayloadAsBytes())
  205. // Log.d("ADVTECH", result)
  206.  
  207. // muutetaan vastaanotettu data JSONista -> WeatherStation -luokan olioksi
  208. var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
  209. Log.d("ADVTECH", item.d.get1().v.toString() + "C")
  210.  
  211.  
  212.  
  213. } jne ...
  214.  
  215.  
  216. Tässä tulee ongelma, koska välillä datan mukanaa tulee ns. diagnostiikkadataa, mikä ei toimi WeatherStation-luokan kanssa, ja GSON tilttaa
  217.  
  218. käytetään try-catchia ettei koodi tilttaa:
  219.  
  220. .callback { publish ->
  221.  
  222. // this callback runs everytime your code receives new data payload
  223. // muutetaan raakadata tekstiksi (tässä tapauksessa JSONia)
  224. var result = String(publish.getPayloadAsBytes())
  225. // Log.d("ADVTECH", result)
  226.  
  227. // try/catch => koodi joka saattaa tiltata laitetaan tryn sisälle:
  228. // catch hoitaa virhetilanteet
  229. // nyt MQTT:stä tulee välillä diagnostiikkadataa, mikä rikkoo GSON-koodin
  230. // try/catch estää ohjelman tilttaamisen
  231. try {
  232. // muutetaan vastaanotettu data JSONista -> WeatherStation -luokan olioksi
  233. var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
  234. Log.d("ADVTECH", item.d.get1().v.toString() + "C")
  235. }
  236. catch(e : Exception) {
  237. Log.d("ADVTECH", e.message.toString())
  238. Log.d("ADVTECH", "Saattaa olla diagnostiikkadataa.")
  239. }
  240.  
  241.  
  242.  
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement