투케이2K

174. (TWOK/UTIL) [Web/JavaScript] paho-mqtt 라이브러리 및 aws4fetch 사용해 AWS IOT Core MQTT 구독 , 메시지 발생 수행 본문

투케이2K 유틸파일

174. (TWOK/UTIL) [Web/JavaScript] paho-mqtt 라이브러리 및 aws4fetch 사용해 AWS IOT Core MQTT 구독 , 메시지 발생 수행

투케이2K 2025. 11. 23. 18:51
728x90

[설 명]

프로그램 : Web / JavaScript

설 명 : [Web/JavaScript] paho-mqtt 라이브러리 및 aws4fetch 사용해 AWS IOT Core MQTT 구독 , 메시지 발생 수행

 

[소스 코드]

-----------------------------------------------------------------------------------------
[사전 설명 및 설정 사항]
-----------------------------------------------------------------------------------------

- 개발 환경 : Web


- 개발 기술 : JavaScript (자바스크립트) / AWS / MQTT / paho-mqtt / aws4fetch


- 사전) MQTT (Message Queuing Telemetry Transport) 설명 : 

  >> MQTT 는 경량 메시지 프로토콜로, 주로 IoT(사물인터넷) 환경에서 사용됩니다

  >> MQTT 목적 : 제한된 네트워크 환경(저속, 불안정)에서 효율적으로 메시지를 주고받기 위해 설계

  >> MQTT 기반 : TCP/IP 위에서 동작

  >> MQTT 패턴 : Publish/Subscribe 모델을 사용

    - Publisher : 메시지를 발행하는 클라이언트

    - Subscriber : 특정 주제(topic)를 구독하는 클라이언트

    - Broker: 메시지를 중개하는 서버 (예: Mosquitto)

  >> MQTT 주요 특징 : 

    - 경량성 : 헤더가 매우 작음(2바이트부터 시작)

    - QoS (Quality of Service) : 
      $ QoS 0: 최대 한 번 전달(보장 없음)
      $ QoS 1: 최소 한 번 전달(중복 가능)
      $ QoS 2: 정확히 한 번 전달(가장 안전)

    - 지속 연결 : KeepAlive로 연결 상태 유지

    - Last Will and Testament (LWT) : 클라이언트 비정상 종료 시 브로커가 메시지 발행

    - 토픽 기반 라우팅 : 계층적 구조(/home/temperature 등)

-----------------------------------------------------------------------------------------





-----------------------------------------------------------------------------------------
[소스 코드]
-----------------------------------------------------------------------------------------


<!DOCTYPE HTML>
<html lang="ko">
<head>
    <title>javaScriptTest</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">


    <!-- 반응형 구조 만들기 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">


    <!-- 내부 CSS 스타일 지정 -->
    <style>

        html, body {
            width: 100%;
            height: 100%;
            margin : 0 auto;
            padding : 0;
            border : none;
            background-color: #666;
        }

    </style>





    <!-- [CDN 주소 설정] : https://www.jsdelivr.com/package/npm/paho-mqtt -->
    <script src="https://cdn.jsdelivr.net/npm/paho-mqtt@1.1.0/paho-mqtt.min.js"></script>






    <!-- [자바스크립트 코드 지정] -->
    <script type="module">

        // --------------------------------------------------------------------------------------------------------------

        // [모듈 import]
        import aws4 from "https://esm.sh/aws4fetch@1.0.17";

        const { AwsClient } = aws4;    

        // --------------------------------------------------------------------------------------------------------------

        // [전역 변수 선언]
        const endpoint = 'a1..pd9-ats.iot.ap-northeast-1.amazonaws.com'; // [AWS iot:Data-ATS 도메인]
        const region = 'ap-northeast-1'; // [AWS 리전]
        const accessKey = 'AK..7Q'; // [IAM 액세스 키]
        const secretKey = 'Zz..xj'; // [IAM 시크릿 키]

        var mqttClient = null;
        var connectTimer = null;
        
        // --------------------------------------------------------------------------------------------------------------

        // [html 최초 로드 및 이벤트 상시 대기 실시]
        window.onload = async function() {
            console.log("");
            console.log("=========================================");
            console.log("[window onload] : [start]");
            console.log("=========================================");
            console.log("");

            try {

                // --------------------------------------
                // AWS : SigV4 인증 URL 생성
                // --------------------------------------
                const aws = new AwsClient({
                    accessKeyId: accessKey,
                    secretAccessKey: secretKey,
                    service: "iotdevicegateway", // ✅ 중요!
                    region: region,
                });

                const url = `wss://${endpoint}/mqtt`; // [AWS iot:Data-ATS 도메인]

                console.log("");
                console.log("=========================================");
                console.log("[window onload] : [aws.sign] : [request]");
                console.log("---------------------------------------");
                console.log("[url] : ", url);
                console.log("=========================================");
                console.log("");

                
                // [SigV4 서명된 URL 생성]
                const signed = await aws.sign(url, { 
                    method: "GET",
                    signQuery: true // ✅ signQuery: true 옵션 추가
                });

                console.log("");
                console.log("=========================================");
                console.log("[window onload] : [aws.sign] : [reponse]");
                console.log("---------------------------------------");

                console.log("[signed all] : ", signed);
                console.log("---------------------------------------");
                console.log("[signed.url] : ", signed.url);
                console.log("=========================================");
                console.log("");

                

                // --------------------------------------
                // Call : Mqtt Connect
                // --------------------------------------
                //mqttConnect("broker.hivemq.com", 8000); // Default

                mqttConnect(signed.url, 0); // AWS WebSocket : wss://<endpoint>/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=...

            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[window onload] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }
        };





        // [Create : Mqtt Object]
        function mqttConnect(url, port) {
            console.log("");
            console.log("=========================================");
            console.log("[mqttConnect] : [start]");
            console.log("---------------------------------------");
            console.log("[url] : ", url);
            console.log("---------------------------------------");
            console.log("[port] : ", port);
            console.log("=========================================");
            console.log("");

            try {
                
                // --------------------------------------
                // Set : Client Id
                // --------------------------------------
                const clientId = "clientId-" + Math.random();


                // --------------------------------------
                // Set : Paho.Client
                // --------------------------------------
                if (port > 0){
                    mqttClient = new Paho.Client(url, port, "clientId-" + Math.random()); // Default
                }
                else { // ✅ port <= 0 : AWS 시도 처리
                    mqttClient = new Paho.Client(url, "clientId-" + Math.random()); // ✅ AWS WebSocket : wss:// 443 자동 할당 
                }

                //mqttClient = new Paho.Client("broker.hivemq.com", 8000, "clientId-" + Math.random()); // Success Test
                //mqttClient = new Paho.Client("tcp://broker.hivemq.com", 8000, "clientId-" + Math.random()); // Fail Test
                //mqttClient = new Paho.Client("broker.hivemq.com", 1883, "clientId-" + Math.random()); // TimeOut Test
                
                console.log("Client created : ", mqttClient);


                // --------------------------------------
                // Set : callback handlers
                // --------------------------------------
                mqttClient.onConnectionLost = onConnectionLost;
                mqttClient.onMessageArrived = onMessageArrived;


                // --------------------------------------
                // Connect : mqttClient
                // --------------------------------------
                console.log("");
                console.log("=========================================");
                console.log("[Mqtt] : connect : start");
                console.log("=========================================");
                console.log("");

                if (port > 0){
                    mqttClient.connect({onSuccess:onConnect}); // Default
                }
                else { // ✅ port <= 0 : AWS 시도 처리
                    mqttClient.connect({
                        
                        useSSL: true, // ✅ SSL/TLS 사용 여부 : 반드시 true 설정
                        mqttVersion: 4, // MQTT 프로토콜 버전 (MQTT v3.1.1)

                        timeout: 20, // 연결 시도 타임아웃 (초) → 기본값은 30초
                        keepAliveInterval: 30, // ✅ Ping 주기 (초) → 기본값은 60초    
                        
                        cleanSession: true, // ✅ 이전 세션 구독 정보 삭제

                        /*
                        invocationContext: { // 연결 시 컨텍스트 객체 → 콜백에서 context로 접근 가능
                            clientId: "mqtt-client"
                        },
                        // */

                        onSuccess:onConnect, // 연결에 따른 콜백
                        onFailure: (err) => console.error("Connection failed : ", err) // 연결에 따른 에러 메시지
                    });                    
                }

                //mqttClient.connect({onSuccess:onConnect});


                // --------------------------------------
                // Connect : TimeOut Handler
                // --------------------------------------
                connectTimer = setTimeout(() => {
                    console.error("");
                    console.error("=========================================");
                    console.error("[Mqtt] : connect : TimeOut");
                    console.error("=========================================");
                    console.error("");

                    try {
                        if (mqttClient != null){
                            mqttClient.disconnect(); // connect clear >> onConnectionLost
                            mqttClient = null;
                        }                        
                    }
                    catch (exception) {

                        // disconnect Fail >> call onConnectionFail
                        try {
                            throw new Error("TimeOut Failed to Connection");
                        }
                        catch (error){
                            if (error.message.indexOf("Failed to") >= 0){
                                onConnectionFail(error);
                            }    
                        }
                        
                    }                    

                }, 5000);

            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[mqttConnect] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");

                if (exception.message.indexOf("Failed to") >= 0){
                    onConnectionFail(exception);
                }
            }
        }





        // [Connection : Callback Handler]
        function onConnect() {

            // --------------------------------------
            // Check : Paho Client
            // --------------------------------------
            if (mqttClient == null){
                return;
            }

            console.log("");
            console.log("=========================================");
            console.log("[Mqtt] : connect : onSuccess");
            console.log("=========================================");
            console.log("");


            // --------------------------------------
            // Clear : Connect TimeOut Timer
            // --------------------------------------
            if (connectTimer != null){
                clearTimeout(connectTimer);
                connectTimer = null;
            }


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {

                //onSubscribe("/TWOK/2K"); // Default : Set Subscribe
                //onPublish("/TWOK/2K", "Hello"); // Default : Send Publish

                // ---------------------------------

                onSubscribe("$aws/things/T_TWK_0000000001/shadow/name/common/update/#"); // Aws Named Shadow : Set Subscribe

                const json = {
                    state: {
                        reported: {
                            command: "COMMON.COMMAND"
                        }
                    }
                }

                onPublish("$aws/things/T_TWK_0000000001/shadow/name/common/update", JSON.stringify(json)); // Aws Named Shadow : Send Publish

                // ---------------------------------

            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onConnect] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }
            
        }





        // [Connection : Callback Handler]
        function onConnectionLost(responseObject) {
            console.error("");
            console.error("=========================================");
            console.error("[Mqtt] : connect : onConnectionLost");
            console.error("---------------------------------------");
            console.error("[responseObject] : ", JSON.stringify(responseObject));
            console.error("---------------------------------------");

            console.error("[errorCode] : ", responseObject.errorCode);
            console.error("---------------------------------------");
            console.error("[errorMessage] : ", responseObject.errorMessage);
            console.error("=========================================");
            console.error("");

            /*
            -----------------------------------------
            [errorCode] : 종류
            -----------------------------------------
            0 : 정상 종료 (예: 클라이언트에서 명시적으로 disconnect() 호출)
            -----------------------------------------
            1 : 소켓 오류 (네트워크 문제로 연결이 끊김)
            -----------------------------------------
            2 : 프로토콜 오류 (MQTT 프로토콜 위반)
            -----------------------------------------
            3 : 메시지 전송 오류 (메시지 처리 중 내부 오류)
            -----------------------------------------
            4 : KeepAlive 타임아웃 (브로커 응답 없음)
            -----------------------------------------
            5 : 내부 오류 (예: AMQJS0005E와 같은 내부 예외)
            -----------------------------------------
            // */


            // --------------------------------------
            // Clear : Connect TimeOut Timer
            // --------------------------------------
            if (connectTimer != null){
                clearTimeout(connectTimer);
                connectTimer = null;
            }


            // --------------------------------------
            // Clear : Mqtt Object
            // --------------------------------------
            try {
                if (mqttClient != null){
                    mqttClient.disconnect(); 
                    mqttClient = null;
                }                        
            }
            catch (exception) { // disconnect error
                console.error("[Mqtt] : onConnectionLost : disconnect : Exception : ", exception.message);  
                mqttClient = null;              
            }


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {

                var onConnectionLostReason = "";

                if (responseObject.errorCode == 0){
                    onConnectionLostReason = String(responseObject.errorCode) + " : 정상 종료 (예: 클라이언트에서 명시적으로 disconnect() 호출)";
                }
                else if (responseObject.errorCode == 1){
                    onConnectionLostReason = String(responseObject.errorCode) + " : 소켓 오류 (네트워크 문제로 연결이 끊김)";
                }
                else if (responseObject.errorCode == 2){
                    onConnectionLostReason = String(responseObject.errorCode) + " : 프로토콜 오류 (MQTT 프로토콜 위반)";
                }
                else if (responseObject.errorCode == 3){
                    onConnectionLostReason = String(responseObject.errorCode) + " : 메시지 전송 오류 (메시지 처리 중 내부 오류)";
                }
                else if (responseObject.errorCode == 4){
                    onConnectionLostReason = String(responseObject.errorCode) + " : KeepAlive 타임아웃 (브로커 응답 없음)";
                }
                else if (responseObject.errorCode == 5){
                    onConnectionLostReason = String(responseObject.errorCode) + " : 내부 오류 (예: AMQJS0005E와 같은 내부 예외)";
                }
                else {
                    onConnectionLostReason = String(responseObject.errorCode) + " : ELSE";
                }

                console.error("");
                console.error("=========================================");
                console.error("[Mqtt] : onConnectionLostReason : ", onConnectionLostReason);
                console.error("=========================================");
                console.error("");
            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onConnectionLost] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }
        }






        // [Connection : Callback Handler]
        function onConnectionFail(error) {
            console.error("");
            console.error("=========================================");
            console.error("[Mqtt] : connect : onConnectionFail");
            console.error("---------------------------------------");
            console.error("[errorName] : ", error.name);
            console.error("---------------------------------------");
            console.error("[errorMessage] : ", error.message);
            console.error("=========================================");
            console.error("");

            
            // --------------------------------------
            // Clear : Connect TimeOut Timer
            // --------------------------------------
            if (connectTimer != null){
                clearTimeout(connectTimer);
                connectTimer = null;
            }


            // --------------------------------------
            // Clear : Mqtt Object
            // --------------------------------------
            try {
                if (mqttClient != null){
                    mqttClient.disconnect(); 
                    mqttClient = null;
                }                        
            }
            catch (exception) { // disconnect error
                console.error("[Mqtt] : onConnectionFail : disconnect : Exception : ", exception.message);      
                mqttClient = null;          
            }


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {

            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onConnectionFail] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }

        }






        // [Topic : Subscribe]
        function onSubscribe(topic) {

            // --------------------------------------
            // Check : Paho Client
            // --------------------------------------
            if (mqttClient == null){
                return;
            }

            console.log("");
            console.log("=========================================");
            console.log("[Mqtt] : onSubscribe : Start");
            console.log("---------------------------------------");
            console.log("[topic] : ", topic);
            console.log("=========================================");
            console.log("");


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {
                mqttClient.subscribe(topic); // Set Topic Subscribe

                console.log("");
                console.log("=========================================");
                console.log("[Mqtt] : onSubscribe : Success");
                console.log("---------------------------------------");
                console.log("[topic] : ", topic);
                console.log("=========================================");
                console.log("");
            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onSubscribe] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }
        }






        // [Topic : Publish]
        function onPublish(topic, message) {

            // --------------------------------------
            // Check : Paho Client
            // --------------------------------------
            if (mqttClient == null){
                return;
            }

            console.log("");
            console.log("=========================================");
            console.log("[Mqtt] : onPublish : Start");
            console.log("---------------------------------------");
            console.log("[topic] : ", topic);
            console.log("---------------------------------------");
            console.log("[message] : ", message);
            console.log("=========================================");
            console.log("");


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {

                const pahoMessage = new Paho.Message(message);
                pahoMessage.destinationName = topic; // Set Topic Publish

                mqttClient.send(pahoMessage);

                console.log("");
                console.log("=========================================");
                console.log("[Mqtt] : onPublish : Success");
                console.log("---------------------------------------");
                console.log("[topic] : ", topic);
                console.log("---------------------------------------");
                console.log("[message] : ", message);
                console.log("=========================================");
                console.log("");
            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onPublish] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }
        }





        // [Receive : Message]
        function onMessageArrived(message) {

            // --------------------------------------
            // Check : Paho Client
            // --------------------------------------
            if (mqttClient == null){
                return;
            }

            console.log("");
            console.log("=========================================");
            console.log("[Mqtt] : receive : onMessageArrived");
            console.log("---------------------------------------");
            console.log("[message] : ", JSON.stringify(message));
            console.log("---------------------------------------");
            console.log("[payloadString] : ", message.payloadString);
            console.log("=========================================");
            console.log("");


            // --------------------------------------
            // Logic : Procedure
            // --------------------------------------
            try {

            }
            catch (exception) {
                console.error("");
                console.error("=========================================");
                console.error("[onMessageArrived] : [Exception] : 예외 상황 발생");
                console.error("-----------------------------------------");
                console.error(exception.name);
                console.error("-----------------------------------------");
                console.error(exception.message);
                console.error("=========================================");
                console.error("");
            }

        }

        // --------------------------------------------------------------------------------------------------------------

    </script>


</head>


<body>

</body>

</html>

-----------------------------------------------------------------------------------------





-----------------------------------------------------------------------------------------
[참고 사이트]
-----------------------------------------------------------------------------------------

[간단 소스] 자바스크립트 paho-mqtt 라이브러리 사용해 MQTT 기본 Connection 연결 수행 실시

https://kkh0977.tistory.com/8414

https://blog.naver.com/kkh0977/224083727154


MQTT (Message Queueing Telemetry Transport) 통신 설명

https://kkh0977.tistory.com/3631

https://blog.naver.com/kkh0977/222971771381?trackingCode=blog_bloghome_searchlist


[라이브러리] [Android] paho.mqtt.android - MqttAndroidClient 안드로이드 MQTT 통신 라이브러리

https://blog.naver.com/kkh0977/223557263865?trackingCode=blog_bloghome_searchlist


[MQTT] mosquitto 사용해 MQTT 통신 테스트 환경 구축

https://blog.naver.com/kkh0977/222971768497?trackingCode=blog_bloghome_searchlist


[mqtt] 온라인 MQTT 테스트 수행 참고 사이트

https://blog.naver.com/kkh0977/223557261164?trackingCode=blog_bloghome_searchlist

-----------------------------------------------------------------------------------------
 
728x90
반응형
Comments