투케이2K

162. (TWOK/LOGIC) [Aws] AWS Iot Core 에서 MQTT 통신 publish 메시지 연속 발생 수행 시 구간 별 딜레이 시간 적용 및 메시지 전송 로직 본문

투케이2K 로직정리

162. (TWOK/LOGIC) [Aws] AWS Iot Core 에서 MQTT 통신 publish 메시지 연속 발생 수행 시 구간 별 딜레이 시간 적용 및 메시지 전송 로직

투케이2K 2025. 12. 5. 09:08
728x90

[로직 정리]

정리 로직 : Aws / Iot / MQTT

상태 : [Aws] AWS Iot Core 에서 MQTT 통신 publish 메시지 연속 발생 수행 시 구간 별 딜레이 시간 적용 및 메시지 전송 로직

 

[설 명]

// --------------------------------------------------------------------------------------
[사전) 설정 및 정보 확인 사항]
// --------------------------------------------------------------------------------------

1. 제 목 : [Aws] AWS Iot Core 에서 MQTT 통신 publish 메시지 연속 발생 수행 시 구간 별 딜레이 시간 적용 및 메시지 전송 로직


2. 테스트 환경 : Aws / Iot / Mqtt / WebSocket / JavaScript / Publish


3. 사전) 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 등)


4. 사전) 자바스크립트에서 MQTT 연결을 위한 MQTT 라이브러리 및 aws4fetch 의존성 설정 코드 : 

  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.7/dayjs.min.js"></script>


  <!-- [자바스크립트 코드 작성 부분에 module 로드 지정] -->
  <script type="module">

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

    const { AwsClient } = aws4;

  </script>

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






// --------------------------------------------------------------------------------------
[로직 설명]
// --------------------------------------------------------------------------------------

1. 자바스크립트 <script> 코드 내에 AWS 연결 및 publish , subscribe 을 위한 전역 변수 선언 수행

  const endpoint = 'a1..d9-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 시크릿 키]

  const thingName = "T_TWOK_0000000001";

  // 메시지 전송 토픽
  const publish_json_empty = {
      state: {
          reported: { // Device Reported
                    
          }
      }
  };

  const publish_topic = `$aws/things/${thingName}/shadow/name/{shadowName}/update`;
  const subscribe_topic = `$aws/things/${thingName}/shadow/name/{shadowName}/update/accepted`;


2. 자바스크립트 window.onload 부분에서 AWS SigV4 인증 객체 생성 수행

  const aws = new AwsClient({
      accessKeyId: accessKey,
      secretAccessKey: secretKey,
      service: "iotdevicegateway", // ✅ 중요!
      region: region,
  });

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


3. aws.sign 을 사용해 SigV4 서명된 URL 생성 실시

  const signed = await aws.sign(url, { 
      method: "GET",
      signQuery: true // ✅ signQuery: true 옵션 추가
  });

  // ✅ wss://a1y..pd9-ats.iot.ap-northeast-1.amazonaws.com/mqtt?X-Amz-Date=20251123T234432Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AK..H7Q%2F20251123%2Fap-northeast-1%2Fiotdevicegateway%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=fcc..d7a
  const signUrl = signed.url;


4. AWS 연결 수행을 위한 MQTT Client 객체 생성 및 이벤트 감지 핸들러 등록

    const clientId = "clientId-" + Math.random();

    mqttClient = mqtt.connect(url, { // Custom Option
            
        clientId: clientId, // 클라이언트 아이디

        protocolVersion: 5, // ✅ 4(MQTT 3.1.1) 또는 5(MQTT 5)
        connectTimeout: (CONNECT_TIME_OUT * 1000), // CONNACK 대기 타임아웃(ms, 기본 30000)
        keepalive: 30, // ✅ Ping 주기 (초) → 기본값은 60초
        clean: true, // 이전 세션 초기화
        resubscribe: false, // 재연결 시 구독 자동 복원(기본 true)
        reconnectPeriod: 0, // 0 값은 자동 재연결 비활성화
    });
                
    mqttClient.on('connect', (connack) => {
        console.warn('[Mqtt] : Connected : ', connack);
    });

    mqttClient.on('reconnect', () => { // 자동 재연결 시도가 시작될 때 호출됩니다 (reconnectPeriod 속성 값 > 0 일때)
        console.warn('[Mqtt] : Reconnecting...');
    });

    mqttClient.on('close', () => { // 연결이 완전히 닫혔을 때(소켓 종료) (onConnectionLost 와 가장 가까운 타이밍)
        console.error('[Mqtt] : Connection closed');

        onConnectionLost('Connection closed');
    });

    mqttClient.on('offline', () => { // 네트워크 단절 등으로 클라이언트가 오프라인 상태가 되었을 때. (재연결 로직이 계속 동작할 수 있음)
        console.error('[Mqtt] : Client is offline');

        onConnectionLost('Client is offline');
    });

    mqttClient.on('error', (err) => { // 연결/인증/프로토콜 오류가 발생했을 때 호출됩니다. 초기 연결 실패 (예: 인증 오류로 CONNACK=Error)도 여기로 들어옵니다.
        console.error('[Mqtt] Connection error : ', err);

        onConnectionLost(err.message);
    });

    mqttClient.on('disconnect', (packet) => { // 브로커가 DISCONNECT 패킷을 보내온 경우(이유 코드 포함)

        console.error('[Mqtt] Disconnected by broker : ', packet);

        onConnectionLost('Disconnected by broker');
    });


    mqttClient.on('message', (topic, payload, packet) => {
        console.warn(`[Mqtt] Message on : topic = ${topic} : payload = `, payload.toString(), ' : packet = ', JSON.stringify(packet));
    });


5. 정상적으로 MQTT Client connect 가 완료 된 경우 특정 토픽 subscribe 구독 수행 실시

    >> ✅ 구독 토픽은 named shadow 총 2개 구독 수행 : 

      - 구독 예시 코드 : $aws/things/${thingName}/shadow/name/{shadowName}/update/accepted

      - shadowName : test1 , test2


    >> subscribe 구독 소스 코드 : 

    mqttClient.subscribe(topic, { 

        qos: QOS, // 네트워크 서비스 품질                    

    }, (err, granted) => {
        
        var timeStamp = String(Date.now()); // 타임스탬프
        var date = dayjs(Number(timeStamp));            
        var nowDate = date.format("YYYY-MM-DD HH:mm:ss");

        if (err) {
            console.error("[Mqtt] : onSubscribe : Error : ", err);
        }
        else {
            console.log("[Mqtt] : onSubscribe : Granted : ", JSON.stringify(granted));
        }
    });


6. 정상적으로 구독이 완료 된 경우 구독 된 토픽 경로 (2개) 로 publish 메시지 연속 전송 수행

    >> ✅ 메시지 전송 토픽은 named shadow 총 2개 : 

      - 메시지 전송 토픽 예시 코드 : $aws/things/${thingName}/shadow/name/{shadowName}/update

      - shadowName : test1 , test2


    >> 자바스크립트 내부 클로저 함수 선언 및 일정 딜레이 시간 추가 연속 publish 메시지 전송 수행

    // -----------------------------------------
    // [내부 클로저 함수 선언]
    // -----------------------------------------
    const innerFunction = async function(topic, message) {

      try {

        mqttClient.publish(topic, message, { // publish

            qos: QOS, // 네트워크 서비스 품질

            retain: false // 메시지를 브로커에 보관하지 않음

        }, (err) => {

            var timeStamp = String(Date.now()); // 타임스탬프
            var date = dayjs(Number(timeStamp));            
            var nowDate = date.format("YYYY-MM-DD HH:mm:ss");

            if (err) {
                console.error("[Mqtt] : onPublish : Error : ", err);
            }
            else {
                console.log("[Mqtt] : onPublish : Success");
            }
        });

      }
      catch(exception){
        console.error("");
        console.error("=========================================");
        console.error("[innerFunction] : [Exception] : ", exception);
        console.error("=========================================");
        console.error("");
      }

    };


    // -----------------------------------------
    // ✅ [내부 클로저 함수 호출]
    // -----------------------------------------
    const publishTimer_1 = setTimeout(() => {
      
      innerFunction(topic, message);

    }, 1000 );    


    // -----------------------------------------
    // ✅ [내부 클로저 함수 호출]
    // -----------------------------------------
    const publishTimer_2 = setTimeout(() => {
      
      innerFunction(topic, message);

    }, 2000 );    


7. 구독하고 있는 onMessageArrived 메시지 수신 부분에서 실시간 메시지 확인 및 publish 로 전송한 값 확인 완료

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






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

[업무 이슈] AWS MQTT Shadow 섀도우 생성 시 http 통신 문제로 순차적 Shadow 생성 문제 - Publish 구간 딜레이 추가

https://kkh0977.tistory.com/8135

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


[MQTT (Message Queueing Telemetry Transport) 통신 설명]

https://kkh0977.tistory.com/3631

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


[간단 소스] 자바스크립트 mqtt.min.js 라이브러리 사용해 AWS MQTT5 사용자속성 userProperties 메시지 전송 및 구독 확인

https://kkh0977.tistory.com/8433

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


[Aws Shadow 섀도우 토픽 구독 및 publish 요청 이후 타임아웃 TimeOut 로직 처리]

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


[android] 안드로이드 aws shadow mqtt 수행 publish , subscribe 결과 확인 - get, update, delete

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

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