본문 바로가기

프로젝트형 IoT 서비스 개발 4회차/3. 게이트웨이 디바이스 제어

[Day69] 2022-05-04(수) Android6 - MQTT 통신(세팅, Publish) - 김서연 강사님

728x90

[1] MQTT 통신

  1. 안드로이드에서 MQTT

    1) build.gradle(module) 파일에 라이브러리 등록 (dependencies 목록에 추가) 및 Sync now 클릭

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

    2) MQTT는 외부 서버와 통신을 하기 때문에 권한 추가

      - AndroidManifest.xml 파일에 추가

    <!--인터넷 접속할 수 있는 권한-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--네트워크에 연결됐는지 확인할 수 있게 하는 권한-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--디바이스가 sleep 상태에 빠지지 않도록-->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    3) MQTT 라이브러리 내부에서 제공되는 Service 클래스를 AndroidManifest.xml 파일에 추가

      - 백그라운드에서 지속적으로 연결을 수행하는 기능이 구현된 라이브러리에서 제공하는 안드로이드 클래스

      - LoopForever와 같은 기능을 별도로 주지 않아도 되도록

<service android:name="org.eclipse.paho.android.service.MqttService"/>

    4) MQTT 통신을 수행할 클래스를 만들고 기능 구현하기

      ① 클라이언트 객체 생성

      ② callback 메소드 정의하고 등록

      ③ connect : connect 하면서 subscribe 하기 위해 topic 등록

    5) publish 할 수 있도록 구현하기

      - Message 객체 만들어서 publish      

      - publish한 후 콜백이 필요한 경우 등록

    6) 서버와의 통신을 하면서 문제없이 통신을 하고 있는지 확인 위해 callback 메소드를 작성하고 등록하고 사용

      - IMqttActionListener의 하위를 작성하고 등록

      - 서버와 connect 후 결과 확인

      - publish 후 확인

      - subscribe 후 확인

  2. Publish

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MqttTestActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btn_led_on"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="led켜기"/>
        <Button
            android:id="@+id/btn_led_off"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="led끄기"/>
    </LinearLayout>
    <EditText
        android:id="@+id/showdata"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />



</LinearLayout>

MyMqtt.kt

package com.example.mqtttestpro

import android.content.Context
import android.util.Log
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*

class MyMqtt(context:Context, uri:String) {
    // 안드로이드에서 mqtt통신을 수행할 객체 -> MqttAndroidClient
    var mqttClient:MqttAndroidClient = MqttAndroidClient(context, uri, MqttClient.generateClientId())

    // mqtt통신을 하기 위해 브로커 서버와 연결, 연결이 끝난 후 콜백메소드 설정
    fun connect(topic:Array<String>){
        // 연결하기 위해서 필요한 여러가지 정보를 담고 있는 객체
        val mqttConnectOptions = MqttConnectOptions()
        // mqttAndroidClient 객체의 connect를 호출하며 브로커에 연결을 시도
        // 안드로이드 내부에서 브로커에 연결을 성공하면 자동으로 이벤트가 발생하며 이를 처리하는 리스너가 IMqttActionListener
        mqttClient.connect(mqttConnectOptions,null, object:IMqttActionListener{
            override fun onSuccess(asyncActionToken: IMqttToken?) {
                // 접속 성공
                Log.d("mymqtt", "브로커 접속 성공....")
            }

            override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                // 접속 실패
                Log.d("mymqtt", "브로커 접속 실패....")
            }
        })
    }

    fun publish(topic:String, payload:String, qos:Int=0){
        if(!mqttClient.isConnected){
            mqttClient.connect()
        }
        val message = MqttMessage()
        // 메시지객체에 payload와 메시지 전송 품질(qos) 설정
        // 네트워크로 전송되도록 byte로 변경
        message.payload = payload.toByteArray()
        message.qos = qos
        // 메시지 전송하기 (publish) - publish가 성공/실패하는 경우 이벤트가 발생하기 때문에 리스너 등록
        // mqttClient.publish(topic, message) // 이렇게만 publish해도 됨
        // publish 후 콜백이 실행되도록 하고 싶다면 다음과 같이 publish
        mqttClient.publish(topic, message, null, object:IMqttActionListener{
            override fun onSuccess(asyncActionToken: IMqttToken?) {
                Log.d("mymqtt", "메시지 전송 성공...")
            }

            override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                Log.d("mymqtt", "메시지 전송 실패...")
            }
        })
    }


}

MqttTestActivity.kt

package com.example.mqtttestpro

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

// 화면디자인 - 화면에 있는 위젯들의 이벤트에 반응하는 처리만 구현
class MqttTestActivity : AppCompatActivity(), View.OnClickListener {
    val sub_topic = "iot/#"
    val server_uri = "tcp://XXX.XXX.XXX.XXX:1883"   // broker의 ip와 port
    var mymqtt:MyMqtt? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // MQTT 통신을 수행할 MQTT 객체를 생성
        mymqtt = MyMqtt(this, server_uri)
        // broker 연결
        mymqtt?.connect(arrayOf<String>(sub_topic))

        // 이벤트 연결
        btn_led_on.setOnClickListener(this)
        btn_led_off.setOnClickListener(this)

    }

    override fun onClick(v: View?) {
        var data:String = ""
        data = if(v?.id==R.id.btn_led_on){
            "led_on"
        }else{
            "led_off"
        }
        mymqtt?.publish("android/led", data)
    }


}

버튼 누를 때마다 해당되는 메시지가 전송
publish된 메시지가 잘 전달되는지 확인

 

- 끝 -

728x90