통신/MQTT

[controller] using MQTT - 1

찬영_00 2025. 5. 29. 21:53
728x90

개발 목표

이번 프로젝트의 단기 목표는 MQTT 메시지를 수신하여 라즈베리파이의 내부 설정을 변경하는 기능을 구현하는 것이다.
장기적으로는 여러 명령어가 추가될 것이므로, 확장 가능한 구조를 갖춘 컨트롤러 프로그램을 만들 예정이다.


개발 환경

  • 개발 PC: Windows 10
    • MQTT 메시지 테스트: MQTT Explorer
  • 타겟 디바이스: Raspberry Pi Zero 2W
    • OS: Debian 11 (bullseye), 32bit
    • GCC: 10.2.1 (Raspbian)
    • Mosquitto: 2.0.11

시스템 정보 확인 명령어

getconf LONG_BIT            # 32비트 확인
cat /etc/*release*          # OS 정보 확인
dpkg -l | grep mosquitto    # Mosquitto 버전 확인

디렉토리 구조

컨트롤러 프로젝트의 구조는 다음과 같다:

/project
│
├── /build       # 컴파일된 .o 파일 저장
├── /include     # 헤더 파일
├── /logs        # 로그 파일 저장
├── /src         # C 소스 파일
├── main.c       # 메인 엔트리 포인트
└── Makefile     # 컴파일 자동화

로그 라이브러리 개발

개발 중에는 printf만으로는 한계가 있다.
초기에 로그 시스템을 도입하면 디버깅과 유지보수가 훨씬 수월해진다.

이번 포스팅에서는 다음과 같이 log_util 라이브러리를 직접 만들어 사용해 보았다:

  • log_util.h
  • log_util.c

로그 레벨은 INFO, DEBUG, WARN, ERROR로 구성하였고, 로그 파일은 /logs 디렉토리에 저장된다.
추가적으로, 로그 파일 크기가 50KB를 넘으면 자동으로 파일을 분할 저장하도록 설계하였다.

 

로직에 대한 정보는 아래 링크를 참고하자.

https://kksp12y.tistory.com/155

 

log_util.c & log_util.h

/** * @brief 로그 디렉토리가 존재하는지 확인하고 없으면 생성한다. * @return 0 성공, -1 실패 */static int ensure_log_dir() { struct stat st; // stat 함수 / LOG_DIR = logs라는 폴더가 없을 때 -1 반환 if (stat(LOG_DIR, &s

kksp12y.tistory.com

 

 


로그 테스트용 main.c 예제

#include <stdio.h>
#include "./include/log_util.h"

#define VERSION "v999.000"

int main() {
    log_print(LOG_LEVEL_INFO, "프로그램 시작 - 버전: %s", VERSION);
    log_print(LOG_LEVEL_DEBUG, "디버그 메시지 테스트");
    log_print(LOG_LEVEL_WARN, "경고 메시지 테스트");
    log_print(LOG_LEVEL_ERROR, "에러 메시지 테스트");

    // 반복 로그 출력으로 로그 파일 분할 테스트
    for (int i = 1; i <= 1000; i++) {
        log_print(LOG_LEVEL_INFO, "반복 로그 테스트 %d회차", i);
    }

    return 0;
}

Makefile 구성

컴파일 자동화를 위해 다음과 같은 Makefile을 작성하였다:

# 컴파일러 지정 (기본 gcc 사용)
CC = gcc

# 컴파일 옵션
# -Iinclude : 헤더 파일을 include 디렉토리에서 찾도록 지정
# -Wall     : 모든 경고 메시지 출력
# -g        : 디버깅 정보 포함 (gdb 등 디버거 사용 가능)
CFLAGS = -Iinclude -Wall -g

# 소스 파일 목록
# main.c 와 src/ 디렉토리 하위의 모든 파일 포함
SRCS = main.c src/*

# 목적 파일(.o) 저장 경로
OBJDIR = build

# 목적 파일 목록
# src/hello.c → build/src/hello.o 형태로 빌드 경로 유지
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))

# 최종 생성할 실행 파일 이름
TARGET = main

# ======================== #
# [기본 타겟] 실행 파일 생성 #
# ======================== #
all: $(TARGET)

# 실행 파일 생성 규칙
# $@ → 목표 파일(main)
# $^ → 모든 의존 파일(.o들)
# $(LDLIBS) 는 외부 라이브러리 링크할 때 사용 가능
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)

# ======================================== #
# 소스 파일 → 목적 파일(.o) 빌드 규칙 정의 #
# - 자동으로 중간 디렉토리 생성 포함      #
# - $< : 현재 컴파일 대상 .c 파일          #
# - $@ : 생성될 목적 파일 경로             #
# ======================================== #
$(OBJDIR)/%.o: %.c
	@mkdir -p $(dir $@)             # 해당 디렉토리가 없으면 생성
	$(CC) $(CFLAGS) -c $< -o $@     # 컴파일하여 목적 파일 생성

# 빌드 디렉토리 수동 생성용 타겟 (선택적으로 사용)
$(OBJDIR):
	mkdir -p $(OBJDIR)

# ========================= #
# 정리(clean) 타겟 정의     #
# 빌드된 파일 및 실행 파일 삭제 #
# ========================= #
clean:
	rm -rf $(OBJDIR) $(TARGET)


결과 확인

컴파일 후 main을 실행하면 다음과 같이 로그 파일이 생성된다:

각 로그 파일에는 다음과 같은 메시지가 기록된다:


마무리

이번 포스팅에서는 로그 시스템을 먼저 구축하여 향후 개발의 기반을 마련했다.
처음에는 단순한 기능처럼 보였지만, 로그 관리를 위한 구조 설계와 구현에는 생각보다 많은 고려가 필요했다.

이후 포스팅에서는 MQTT 수신 기능 및 명령어별 분기 처리 등을 개발해나갈 예정이다.
꾸준히 업데이트하며 진행 과정을 공유해보겠다.

 

 

 

728x90

'통신 > MQTT' 카테고리의 다른 글

[controller] using MQTT (들어가기 앞서)  (0) 2025.05.26
raspberry pi zero 2 W에 mosquitto 설치  (0) 2025.04.27
mqtt - bin파일 전송 -2  (0) 2025.04.18
mqtt - bin파일 전송  (0) 2025.04.17
MQTT Explorer  (0) 2025.03.24