본문 바로가기
업무 자동화

PyQt로 BMS 모니터링 UI 만들기: 코딩 초보도 3시간에 완성

by 전장엔지니어 DON 2026. 4. 27.

도입부

시험 결과를 엑셀로 받아서 눈으로 하나하나 확인하고 계신가요?

저도 10년 전에는 그랬습니다. BMS(Battery Management System, 배터리 관리 시스템) 시험 로그가 수만 줄씩 쌓이는데, 이상 값을 발견하려면 스크롤을 수백 번씩 내려야 했습니다. "이걸 자동으로 보여주는 화면이 있으면 얼마나 좋을까"라는 생각이 머릿속을 떠나지 않았죠.

그 고민의 결과물이 바로 PyQt 기반 BMS 모니터링 UI입니다. Python과 PyQt5 라이브러리를 활용하면, 코딩을 많이 몰라도 3~4시간 안에 실무에서 쓸 수 있는 모니터링 화면을 만들 수 있습니다. 이번 글에서는 제가 실제로 만들어 쓰고 있는 UI의 구조와 핵심 코드를 초보자 눈높이에 맞춰 설명해 드립니다.


1. 왜 PyQt인가? — 엔지니어가 선택하는 이유

UI 프레임워크는 여러 가지가 있습니다. Tkinter, PyQt, wxPython, Kivy 등 선택지가 많지만, 저는 엔지니어 업무에 PyQt5를 추천합니다. 이유는 세 가지입니다.

① 공식 Qt 기반이라 문서와 예제가 풍부합니다.
Qt(큐트)는 산업용 UI 개발에서 수십 년간 검증된 프레임워크입니다. 자동차, 의료기기, 산업용 장비 UI에 폭넓게 쓰이며, 한국어 자료도 많습니다.

② 위젯(widget, 화면 구성 요소)이 강력하고 직관적입니다.
그래프(pyqtgraph), 테이블, LED 상태 표시, 슬라이더 등 엔지니어가 자주 쓰는 요소를 라이브러리 하나로 해결할 수 있습니다.

③ Python과 완벽히 연동됩니다.
시험 로그 파싱, CAN(Controller Area Network, 차량 내부 통신망) 데이터 수신, Excel 저장 등 엔지니어가 이미 쓰는 Python 코드와 자연스럽게 붙일 수 있습니다.

실제로 제 팀에서는 PyQt5 + pyqtgraph 조합으로 만든 모니터링 화면이 시험 이상값 발견 시간을 기존 대비 약 70% 단축하는 효과를 가져왔습니다.


2. 개발 환경 세팅 — 10분이면 끝납니다

먼저 필요한 라이브러리를 설치합니다. 터미널(명령 프롬프트)에서 아래 명령어를 입력하세요.

pip install PyQt5 pyqtgraph numpy pandas

설치 항목 설명:

  • PyQt5 — UI 프레임워크 본체
  • pyqtgraph — 실시간 그래프 (matplotlib보다 10배 빠름)
  • numpy — 숫자 배열 처리
  • pandas — CSV/Excel 로그 파일 읽기

설치가 완료되면 Python 파일 하나를 만들고 아래 코드를 붙여넣기 해서 실행해 보세요. 창이 열리면 성공입니다.

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel

app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle("BMS 모니터링")
window.setGeometry(100, 100, 800, 600)
label = QLabel("BMS 모니터링 시작!", window)
label.move(300, 280)
window.show()
sys.exit(app.exec_())

딱 12줄로 창 하나가 뜹니다. 이게 PyQt의 매력입니다.


3. BMS 모니터링 UI 핵심 구조 설계

실무에서 BMS 모니터링 화면에 반드시 들어가야 할 요소는 다음 네 가지입니다.

① 실시간 파형 그래프
셀 전압(Cell Voltage), 전류(Current), 온도(Temperature)를 시간 축으로 보여주는 그래프. 이상값이 발생하면 한눈에 보이도록 경고선(threshold line)을 함께 표시합니다.

② 현재값 패널 (Status Panel)
지금 이 순간의 전압/전류/SOC(State of Charge, 충전 상태)/SOH(State of Health, 배터리 건강 상태) 수치를 크게 표시합니다. 숫자가 정상 범위이면 초록색, 경고 범위이면 노란색, 위험 범위이면 빨간색으로 자동 변경됩니다.

③ 알람 로그 (Alarm Log)
OVP(Over Voltage Protection, 과전압 보호), UVP(Under Voltage Protection, 저전압 보호), OTP(Over Temperature Protection, 과온도 보호) 등 BMS 보호 기능이 트리거된 이벤트를 시각과 함께 기록합니다.

④ 데이터 저장 버튼
현재 화면의 데이터를 CSV나 Excel 파일로 저장합니다. 보고서 작성 시간을 절반으로 줄여줍니다.

# BMS 모니터링 핵심 레이아웃 예시
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget,
                              QVBoxLayout, QHBoxLayout, QLabel, QPushButton)
import pyqtgraph as pg
import numpy as np, sys

class BMSMonitor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("BMS 실시간 모니터링 v1.0")
        self.setGeometry(100, 100, 1200, 700)

        # 메인 레이아웃
        central = QWidget()
        self.setCentralWidget(central)
        main_layout = QHBoxLayout(central)

        # 왼쪽: 그래프 영역
        graph_layout = QVBoxLayout()
        self.voltage_plot = pg.PlotWidget(title="셀 전압 (V)")
        self.voltage_plot.addLine(y=4.2, pen=pg.mkPen('r', width=1, style=pg.QtCore.Qt.DashLine))  # OVP 경고선
        self.voltage_plot.addLine(y=2.5, pen=pg.mkPen('r', width=1, style=pg.QtCore.Qt.DashLine))  # UVP 경고선
        graph_layout.addWidget(self.voltage_plot)

        self.temp_plot = pg.PlotWidget(title="온도 (°C)")
        self.temp_plot.addLine(y=60, pen=pg.mkPen('orange', width=1))  # OTP 경고선
        graph_layout.addWidget(self.temp_plot)
        main_layout.addLayout(graph_layout, 3)

        # 오른쪽: 상태 패널
        status_layout = QVBoxLayout()
        self.volt_label = QLabel("전압: -- V")
        self.soc_label = QLabel("SOC: -- %")
        self.temp_label = QLabel("온도: -- °C")
        for lbl in [self.volt_label, self.soc_label, self.temp_label]:
            lbl.setStyleSheet("font-size: 18px; font-weight: bold; padding: 10px;")
            status_layout.addWidget(lbl)

        save_btn = QPushButton("💾 데이터 저장")
        save_btn.clicked.connect(self.save_data)
        status_layout.addWidget(save_btn)
        status_layout.addStretch()
        main_layout.addLayout(status_layout, 1)

    def save_data(self):
        import pandas as pd
        # 실제 데이터를 DataFrame으로 저장
        print("데이터 저장 완료!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = BMSMonitor()
    win.show()
    sys.exit(app.exec_())

이 코드를 실행하면 전압·온도 그래프와 상태 패널이 있는 화면이 완성됩니다.


4. 실시간 데이터 연결 — CAN 또는 CSV 파일 읽기

UI 화면을 만들었으면 이제 실제 데이터를 연결할 차례입니다. 두 가지 방법을 소개합니다.

방법 A: CSV 로그 파일 실시간 읽기 (가장 쉬운 방법)

from PyQt5.QtCore import QTimer
import pandas as pd

# 타이머로 0.1초마다 CSV 파일 재읽기
self.timer = QTimer()
self.timer.timeout.connect(self.update_plot)
self.timer.start(100)  # 100ms = 0.1초

def update_plot(self):
    df = pd.read_csv("bms_log.csv")
    voltage_data = df["voltage"].values[-200:]  # 최근 200개 데이터
    self.voltage_plot.plot(voltage_data, pen='c', clear=True)

    latest = df.iloc[-1]
    self.volt_label.setText(f"전압: {latest['voltage']:.3f} V")
    self.soc_label.setText(f"SOC: {latest['soc']:.1f} %")

방법 B: python-can 라이브러리로 CAN 버스 실시간 수신

import can

bus = can.interface.Bus(channel='PCAN_USBBUS1', bustype='pcan')

def read_can_message():
    msg = bus.recv(timeout=0.01)
    if msg and msg.arbitration_id == 0x1A0:  # BMS 전압 메시지 ID
        voltage = int.from_bytes(msg.data[0:2], 'big') * 0.001  # 스케일링
        return voltage
    return None

처음에는 방법 A로 시작하고, 익숙해지면 방법 B로 업그레이드하는 것을 추천합니다.


5. 색상 자동 변환 — 이상값을 한눈에 파악하는 핵심 기능

가장 실용적인 기능은 수치 범위에 따라 라벨 색상이 자동으로 바뀌는 것입니다. OVP 기준(4.2V)을 초과하면 빨간색으로 바뀌어 즉시 알 수 있습니다.

def update_status_color(self, label, value, warn_low, warn_high, danger_low, danger_high):
    """수치 범위에 따라 라벨 색상 자동 변환"""
    if value < danger_low or value > danger_high:
        color = "#FF4444"   # 빨간색 — 위험
    elif value < warn_low or value > warn_high:
        color = "#FFA500"   # 주황색 — 경고
    else:
        color = "#44BB44"   # 초록색 — 정상

    label.setStyleSheet(
        f"font-size: 18px; font-weight: bold; "
        f"color: {color}; padding: 10px; border: 2px solid {color}; border-radius: 8px;"
    )

# 사용 예시: 전압 3.0~4.2V 정상, 2.7~4.25V 경고, 그 외 위험
self.update_status_color(self.volt_label, current_voltage,
                          warn_low=3.0, warn_high=4.2,
                          danger_low=2.5, danger_high=4.25)

이 30줄짜리 함수 하나가 "이상값을 놓쳐서 시험 실패"하는 상황을 막아줍니다.


마무리 — 도구를 만드는 엔지니어가 살아남습니다

PyQt 모니터링 UI는 처음 만들 때는 낯설지만, 한 번 완성하고 나면 매일 30분 이상 절약되는 효과를 체감합니다. 제 경험상 첫 번째 버전은 3시간, 두번째 버전은 2시간이면 새로운 UI를 뚝딱 만들 수 있습니다.

코딩 초보라도 괜찮습니다. 위 예제 코드를 복사해서 수치만 바꿔가며 시작해 보세요. 처음 화면이 떴을 때의 그 성취감을 맛보면, 그 다음 기능을 추가하는 것이 놀이처럼 느껴집니다. 코딩을 잘 모르시는 분들이라면 생성형 AI또는 Agent AI의 도움을 받아 원하는 UI를 작성하시는 방법도 강력 추천드립니다.

📌 함께 읽으면 좋은 글

다음 글 예고: "pySerial로 BMS 시험 리그 자동화하기 — 버튼 한 번으로 시험 시작부터 데이터 저장까지" 편을 준비하고 있습니다. 댓글로 어떤 기능이 가장 궁금하신지 알려주시면 다음 글에 반영하겠습니다! 😊


태그: #PyQt #BMS모니터링 #업무자동화 #Python #UI개발 #전장엔지니어 #배터리시험 #데이터시각화 #코딩입문 #HiL테스트