[실습] 웹에서 라즈베리파이 LED 유뮤선 제어
필기자
2025-05-05 20:51
1,271
0
본문
웹에서 라즈베리파이 LED 유뮤선 제어
목적
목차
1. 전체 시스템 이해 및 시스템 설치

2. 프론트엔드 및 서버프로그램 개발
목적
- 아파치웹서버와 파이썬 Soket.io 서버를 구성한다.
- 내 PC에서 웹 프라우져(크롬)으로 라즈베리파이 LED를 제어한
목차
1. 전체 시스템 이해 및 시스템 설치
2. 프론트엔드 및 서버프로그램 개발
2. 프론트엔드 및 서버프로그램 개발
1. 전체 시스템 이해 및 시스템 설치
- 구성요소
- 브라우저 (Chrome)
- 사용자가 시스템에 접속하는 클라이언트 도구임.
- Apache 웹 서버에 접속해 프론트엔드 프로그램을 로드함.
- 브라우저는 사용자가 웹 주소를 입력할 때 처음 실행되는 프로그램으로, HTML/CSS/JS로 구성된 화면을 보여주는 역할을 함.
- 사용자가 시스템에 접속하는 클라이언트 도구임.
- Apache 웹 서버 (포트 80)
- HTML, CSS, JavaScript 등 정적 리소스를 브라우저에 제공함.
- 실시간 통신은 담당하지 않음.
- Apache는 가장 널리 사용되는 오픈소스 웹 서버로, 정적 파일을 브라우저에 전달해 웹페이지를 구성하는 역할을 함.
- Python Socket.IO 서버 (포트 5000)
- 웹소켓 기반의 실시간 양방향 통신을 처리함.
- 프론트엔드의 LED 제어 요청 및 상태 응답을 처리함.
- Socket.IO는 WebSocket을 이용해 서버와 클라이언트 간 실시간 데이터를 빠르게 주고받도록 도와주는 라이브러리임.
- 브라우저 (Chrome)

- 동작 흐름
- 브라우저가 Apache 서버에 HTTP 요청을 보냄.
- Apache 서버가 프론트엔드 프로그램을 브라우저에 제공함.
- 프론트엔드는 Socket.IO 서버와 WebSocket 연결을 생성함.
- 사용자 동작에 따라 LED 제어 명령을 서버에 전송함.
- 서버는 GPIO를 통해 하드웨어를 제어하고 상태를 응답함.

//https://mermaid.live/
%%{init: {'themeVariables': {
'fontSize': '18px',
'clusterBkg': '#FFFFFF',
'clusterBorder': '#333333',
'clusterFontSize': '22px',
'nodeSpacing': 50,
'rankSpacing': 80
}}}%%
flowchart TB
%% 노드 정의
Browser["Chrome 브라우저"]
Frontend["프론트엔드 프로그램<br>(HTML, CSS, JavaScript)"]
Apache["Apache 웹 서버<br>(포트 80)"]
SocketIO["Python Socket.IO<br>서버(포트 5000)"]
Hardware["하드웨어 인터페이스<br>GPIO 컨트롤러"]
LED["LED 하드웨어"]
%% 연결 흐름
Browser -- "HTTP 요청" --> Apache
Apache -- "프론트엔드 프로그램 전송" --> Browser
Browser --> Frontend
Frontend -- "WebSocket 연결" --> SocketIO
Frontend -- "LED 제어 요청" --> SocketIO
SocketIO -- "LED 상태 전송" --> Frontend
SocketIO -- "GPIO 제어 명령" --> Hardware
Hardware -- "LED 신호 전송" --> LED
LED -- "상태 피드백" --> Hardware
%% 서브그래프
subgraph client[" "]
Browser
Frontend
end
subgraph server[" "]
Apache
SocketIO
Hardware
end
%% 스타일 정의
classDef client fill:#FFE0E0,stroke:#FF0000,stroke-width:3px
classDef server fill:#E0E0FF,stroke:#0000FF,stroke-width:3px
classDef led fill:#E0FFE0,stroke:#00AA00,stroke-width:3px
%% 스타일 적용
class client client
class server server
class LED led
- 구성 이유
- 정적 콘텐츠와 동적 통신 분리
- Apache는 HTML, CSS, JS 같은 정적인 파일만 제공하므로 요청 처리 속도가 빠르고 안정적임.
- 실시간 통신은 별도의 Socket.IO 서버가 담당하여 처리 부담을 분산함.
- 역할별 모듈화
- 웹 서버와 실시간 서버를 분리하면 유지보수와 확장에 유리함.
- 각 모듈의 기능이 명확하게 분리되어 구조가 단순하고 이해하기 쉬움.
- 실시간 제어에 적합한 구조
- LED 같은 물리적 장치는 빠른 반응이 필요하므로 WebSocket 기반 통신이 적합함.
- Socket.IO는 실시간 이벤트 기반 구조로 지연 없이 상태 전송이 가능함.
- 개발 및 테스트 용이
- 프론트엔드는 Apache로 언제든 새로고침 테스트 가능하고,
- 서버 로직은 Python 단에서 독립적으로 개발 및 디버깅 가능함.
- 정적 콘텐츠와 동적 통신 분리
- 라즈베리파이os에서 apache2 서버 설치
- apt 패키지 도구로 apache2 서버 설치
- /var/www/html 소유권 변경
sudo apt update
#아파치 설치
sudo apt install apache2 -y
#아파치 상태 확인
sudo systemctl status apache2
#아파치 리부팅시 자동시작
sudo systemctl enable apache2
#아파치 root 폴더 권한 변경
sudo chown -R pi:pi /var/www/html
2. 프론트엔드 및 서버프로그램 개발
- apaceh2 home 폴더에 프론트프로그램 개발
- /var/www/html 폴더안에 index.html 파일 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LED 제어</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
</head>
<body>
<h3>LED 제어</h3>
<label><input type="radio" name="led" value="on"> ON</label>
<label><input type="radio" name="led" value="off"> OFF</label>
<p id="status">LED 상태: 알 수 없음</p>
<script>
const socket = io("http://라즈베리파이_IP:5000");
socket.on("connect", function() {
socket.emit("get_led_status");
});
socket.on("led_status", function(data) {
$("#status").text("LED 상태: " + data.state);
$("input[name='led'][value='" + data.state + "']").prop("checked", true);
});
$("input[name='led']").change(function() {
const state = $(this).val();
socket.emit("led_control", { state: state });
});
</script>
</body>
</html>
- 우분투 환경에서 가상 GPIO 사용
- 라즈베리파이 환경이 아닌 우분투 같은 테스트 환경에서 사용
- GPIO 코드 사용시 에러 대체함
- mockgpio.py 파일 생성
# mockgpio.py
class MockGPIO:
BCM = 'BCM'
BOARD = 'BOARD'
OUT = 'OUT'
IN = 'IN'
LOW = 0
HIGH = 1
_pin_states = {}
def setmode(self, mode):
print(f"[MOCK] GPIO mode set to {mode}")
def setup(self, pin, mode):
self._pin_states[pin] = self.LOW
print(f"[MOCK] GPIO pin {pin} set as {mode}")
def output(self, pin, value):
self._pin_states[pin] = value
print(f"[MOCK] GPIO pin {pin} output set to {value}")
def input(self, pin):
value = self._pin_states.get(pin, self.LOW)
print(f"[MOCK] GPIO pin {pin} read as {value}")
return value
def cleanup(self):
self._pin_states.clear()
print("[MOCK] GPIO cleanup complete")
GPIO = MockGPIO()
- iot 가상환경에 socket.io서버 프로그램 개발
- pip install flask flask-socketio eventlet 설치
- home/iot/iot_socket.py 파일 생성
pi@pi20221234:~ $ iot_
(iot) pi@pi20221234:~/iot $ pip install flask flask-socketio eventlet
from flask import Flask
from flask_socketio import SocketIO
from flask import request
try:
import RPi.GPIO as GPIO
except (ImportError, RuntimeError):
from mockgpio import GPIO # 인스턴스를 직접 가져옴
# GPIO 초기화
LED_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)
# Flask 및 SocketIO 설정
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", async_mode="eventlet")
# 현재 LED 상태 반환 함수
def get_led_state():
return "on" if GPIO.input(LED_PIN) else "off"
# 클라이언트로부터 제어 요청 수신
@socketio.on("led_control")
def control_led(data):
state = data.get("state")
if state == "on":
GPIO.output(LED_PIN, GPIO.HIGH)
elif state == "off":
GPIO.output(LED_PIN, GPIO.LOW)
# 상태 응답
state = get_led_state()
print(f"led 상태 : {state}")
socketio.emit("led_status", {"state": state}, room=request.sid)
# 초기 상태 요청 처리
@socketio.on("get_led_status")
def handle_status_request():
state = get_led_state()
print(f"led 상태 : { get_led_state()}")
socketio.emit("led_status", {"state": state}, room=request.sid)
# 서버 실행
if __name__ == "__main__":
socketio.run(app, host="0.0.0.0", port=5000)
댓글목록0