Repository: SmartX-Labs/SmartX-Mini
Pull request #76: Update Lab#3, #4 Experiment Manual
Author: login: Kimcheolhui
Created: 2025-03-04T16:14:27Z | Merged: 2025-03-12T00:02:16Z

Lab#3와 #4의 매뉴얼 수정 완료했습니다.

1. Lab#3
- 장표 이미지 추가 및 수정
- 기존 매뉴얼 내용 수정 및 보충
- 실습 단계 추가(모니터링 대시보드)

2. Lab#4
- 장표 이미지 추가 및 수정
- 기존 매뉴얼 내용 수정 및 보충
- oudated 도커 이미지 재빌드

추가된 내용
- (#897620b) Adafruit_python_DHT에 대한 설명 추가
- (#5e90fcd) typo 수정
- (#bb57195) Lab subtopic 수정


Diff:
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/Lab#3_IoT_kr.md b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/Lab#3_IoT_kr.md
new file mode 100644
index 0000000..47efff7
--- /dev/null
+++ b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/Lab#3_IoT_kr.md	
@@ -0,0 +1,301 @@
+# Lab#3. IoT Lab
+
+## 0. Objective
+
+<img width="916" alt="image" src="https://user-images.githubusercontent.com/63437430/161034315-b201ae9e-463e-44d3-a02f-4796a90f6ee4.png">
+
+**이번 Lab의 목표는 IoT 센서를 활용하여 데이터를 수집하고, 이를 서버에 전달하는 IoT-Cloud Hub를 구축하는 것입니다.**
+
+### 0-1. Lab Goal
+
+- 라즈베리파이를 이용한 IoT 센서 데이터 수집
+- 센서 데이터를 클라우드 서버로 전송
+- Node.js 기반의 웹 서버를 통해 실시간 데이터 시각화
+
+이번 Lab에서는 라즈베리파이(Raspberry Pi) 를 사용하여 센서 데이터를 수집하고, 이를 NUC 서버에서 처리하여 시각화하는 과정을 실습합니다.
+
+### 0-2. IoT-Cloud 시스템이 왜 필요한가?
+
+IoT 기기에서 수집되는 데이터는 개별적으로는 의미가 크지 않지만, 이를 클라우드에서 통합 및 분석하면 강력한 정보나 인사이트를 얻을 수 있습니다. 이러한 데이터는 실시간 모니터링, 자동화, 원격 제어 등의 다양한 분야에서 활용됩니다. Tower Lab에서 진행한 모니터링 시스템 구축과 그 필요성이 비슷하며, 이 Lab에서는 IoT를 활용한 모니터링 시스템이라고 볼 수 있습니다.
+
+### 0-3. Node.js
+
+Node.js는 오픈 소스, 크로스 플랫폼을 지원하는 백엔드 JavaScript 런타임 환경으로, V8 엔진에서 실행되며 웹 브라우저 외부에서도 JavaScript 코드를 실행할 수 있습니다. Node.js를 사용하면 개발자가 JavaScript로 명령줄 도구(Command Line Tool)를 작성하거나, 서버 측 스크립트(Server-Side Scripting)를 실행하여 웹 페이지가 사용자에게 전송되기 전에 동적으로 콘텐츠를 생성할 수 있습니다. 결과적으로, Node.js는 "JavaScript everywhere" 패러다임을 실현하여, 서버와 클라이언트에서 각각 다른 언어를 사용할 필요 없이 단일 프로그래밍 언어(JavaScript)로 웹 애플리케이션을 개발할 수 있도록 해줍니다. 이번 Lab에서는 IoT 센서 데이터를 저장하고 간단한 시각화를 위해 Node.js를 사용합니다.
+
+### 0-4. Adafruit_python_DHT
+
+온습도 센서를 손쉽게 사용하기 위해 Adafruit_python_DHT를 사용합니다. Adafruit_python_DHT는 Adafruit에서 제공하는 Python 라이브러리로, DHT11, DHT22, AM2302 등의 온습도 센서를 Raspberry Pi 및 BeagleBone과 같은 SBC(Single Board Computer)에서 쉽게 사용할 수 있도록 지원합니다. 이 라이브러리는 센서 데이터를 읽고 처리하는 기능을 제공하며, 간단한 Python 코드로 온도 및 습도를 측정할 수 있습니다.
+
+## 1. Preparation
+
+<img src="img/pi-gpio.png" alt="pi gpio" width="450">
+
+위 이미지는 라즈베리파이의 **GPIO(General Purpose Input/Output, 범용 입출력) 핀 배치도**를 나타냅니다. GPIO는 라즈베리파이에서 외부 장치와 연결하여 전기 신호를 주고 받을 수 있는 핀입니다. 간단히 말해, 센서, LED, 모터 등 다양한 기기를 연결하여 입력을 받거나 출력을 보낼 수 있는 다목적 핀이라고 볼 수 있습니다.
+
+- 빨간색 핀(3.3V 전원): 이 핀은 3.3V 전원을 출력하며, 저전력 센서 및 기타 주변 장치에 안정적인 전압을 공급하는 데 사용됩니다.
+- 노란색 핀(GPIO4): 일반적인 GPIO 핀으로, 다양한 입력 및 출력 역할을 수행할 수 있습니다.
+- 검은색 핀(GND): 전자의 흐름이 돌아오는 길(기준점) 역할을 합니다. 센서나 LED를 연결할 때 전원(여기서는 3.3V)과 함께 항상 필요한 핀입니다.
+
+> **이제 위 사진의 빨간색 상자 내부처럼 라즈베리파이에 온습도 센서를 연결해줍니다. 실물 사진은 아래를 참고해주세요!**
+
+<img src="img/pi-sensor.png" alt="pi with sensor" width="450">
+
+<img src="img/pi-sensor-detail.png" alt="pi with sensor" width="450">
+
+---
+
+## 2. Practice
+
+### 2-1. Node.js 웹 서버를 위한 Docker Container 실행 ( in NUC )
+
+#### 2-1-1. Docker Container 실행
+
+아래의 준비된 도커 컨테이너 이미지를 띄워주세요.
+
+(\*연구실에서 수정 작업을 했기 때문에 저 dns가 꼭 필요한지 확인하지 못했으나, 마지막 확인 작업 때 dns 없이도 잘 돌아가는지 확인하고 삭제할 것)
+
+```bash
+sudo docker run -it --net host --dns 203.237.32.100 --name webserver cheolhuikim/smartx-box-mini
+```
+
+컨테이너 내부에 진입하면 아래 명령어를 실행해주세요.
+
+```bash
+apt-get update
+
+apt-get install vim
+```
+
+### 2-2. 웹 서버 코드 수정하기 (NUC)
+
+아래 명령어를 입력해 웹 서버 코드를 확인하고, `<NUC IP>`를 여러분의 NUC IP로 수정해주세요.
+
+```bash
+vi /SmartX-Mini/IoT-labs/webserver.js
+```
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160828580-7201f53f-e66a-40d3-8682-ca237476b20a.png">
+
+### 2-3. 온습도 센서 테스트 ( in PI )
+
+이제 라즈베리파이에 연결된 온습도 센서가 제대로 동작하는지 확인하겠습니다.
+
+#### 2-3-1. Install package
+
+아래 명령어를 입력해 필요한 파일들을 다운로드 해주세요
+
+```bash
+git clone https://github.com/adafruit/Adafruit_python_DHT.git
+```
+
+> **Adafruit_python_DHT?** `0-4. Adafruit_python_DHT` 참고
+
+라즈베리파이 버전 4를 3으로 인식할 수 있도록 Adafruit_DHT의 패키지 Installer를 수정해줘야합니다.
+
+> **Why?** 라즈베리파이 4의 SoC(System on Chip)는 BCM2711이지만, 기존 Adafruit_python_DHT 라이브러리는 이를 인식하지 못하고 기본적으로 지원하는 BCM2835, BCM2837 등과 다르게 처리합니다. 따라서, platform_detect.py 파일에서 BCM2711을 Pi 3으로 인식하도록 설정하면 라이브러리가 정상적으로 작동하며, 추가적인 호환성 문제 없이 센서 데이터를 읽을 수 있습니다.
+
+우선, 파일을 열어줍니다
+
+```bash
+cd Adafruit_python_DHT
+
+sudo vi Adafruit_DHT/platform_detect.py
+```
+
+**BCM2711**에 대한 case를 `pi_version` 함수에 추가해주고, 3을 return하도록 합니다.
+
+```python
+def pi_version():
+    …
+    elif match.group(1) == 'BCM2835':
+        # Pi 3 or Pi 4
+        return 3
+    elif match.group(1) == 'BCM2837':
+        # Pi 3b+
+        return 3
+    elif match.group(1) == 'BCM2711': # 추가
+        # Pi 4b
+        return 3                      # 추가
+    else:
+        # Something else, not a pi.
+        return None
+
+```
+
+패키지 Installer를 수정했으므로, 이제 필요한 패키지들을 설치해줍니다. 약간 시간이 걸릴 수 있습니다.
+
+```bash
+
+sudo apt-get update
+
+sudo apt-get install python3-pip
+
+sudo python3 -m pip install --upgrade pip setuptools wheel
+
+sudo apt install -y build-essential python3-dev
+
+sudo pip3 install .
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|     Package     |   Version   |
+| :-------------: | :---------: |
+|   python3-pip   | 18.1-5+rpt1 |
+| build-essential |    12.6     |
+|   python3-dev   |   3.7.3-1   |
+
+##### Python
+
+|  Package   |   Version   |
+| :--------: | :---------: |
+| setuptools |  40.8.0-1   |
+|   wheel    | 18.1-5+rpt1 |
+
+</details>
+<br>
+
+#### 2-3-2. 온습도 센서 테스트 ( in PI )
+
+예제 폴더로 이동합니다.
+
+```bash
+cd ~/Adafruit_python_DHT/examples
+```
+
+테스트 코드를 열고, `python`을 `python3`로 수정합니다
+
+```bash
+sudo vi AdafruitDHT.py
+```
+
+From
+
+```python
+#!/usr/bin/python
+...
+
+```
+
+To
+
+```python
+#!/usr/bin/python3
+...
+
+```
+
+테스트 코드를 실행합니다.
+
+```bash
+sudo ./AdafruitDHT.py 11 4
+```
+
+아래와 같이 온도와 습도가 잘 표기됐다면, 온습도 센서가 라즈베리파이에 제대로 연결된 것을 의미합니다. 만약 오류가 발생한다면, 아래 순서를 따라주세요.
+
+1. `1. Preparation`으로 돌아가서 온습도 센서의 핀이 올바른 GPIO 핀에 꽂혀있는지 확인해주세요.
+2. 아무런 문제를 발견하지 못했다면, 패키지 설치가 제대로 됐는지 확인해주세요. 패키지를 다시 설치해보는 것도 방법이 될 수 있습니다.
+3. 센서 자체의 문제일 수 있습니다. 만약 여전히 문제가 해결되지 않았다면, 조교를 호출해주세요.
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160829118-04bae048-2cf3-4c3f-8cd9-4b9295b019d0.png">
+
+### 2-4. 센서 데이터 수집과 전송 ( in PI )
+
+이번에는 라즈베리파이에서 수집한 센서 데이터를 NUC으로 전달하기 위해, 관련 코드를 수정하겠습니다.
+
+#### 2-4-1. 필요한 패키지 설치
+
+```bash
+sudo apt-get update
+
+sudo apt-get install python3-numpy
+
+sudo apt-get install mercurial
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|    Package    |     Version     |
+| :-----------: | :-------------: |
+| python3-numpy |   1:1.16.2-1    |
+|   mercurial   | 4.8.2-1+deb10u1 |
+
+</details>
+<br>
+
+#### 2-4-2. 센서 데이터 수집 코드
+
+센서 데이터 수집 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_capture.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829267-f2198912-a27d-4ee3-9b44-e5af753aff6d.png">
+
+#### 2-4-3. 센서 데이터 전송 코드
+
+센서 데이터 전송 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_transfer.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829383-8053b56c-a4ea-42d1-b4d1-220502b7754a.png">
+
+### 2-5. IoT Web Service 실행하기
+
+이제 지금까지 작업한 내용을 바탕으로 간단한 IoT Web Service를 실행하도록 하겠습니다.
+
+#### 2-5-1. Web Server 실행하기 ( in NUC )
+
+NUC에서 실행했던 도커 컨테이너 내부에서 다음의 명령어를 실행해주세요. 다음의 명령어는 `webserver.js`라는 웹서버 코드를 실행합니다.
+
+```bash
+cd /SmartX-Mini/IoT-labs
+
+nodejs webserver.js
+```
+
+#### 2-5-2. 센서 데이터를 수집하고 전송하기 ( in PI )
+
+다음의 명령어를 실행해주세요. `process.sh`는 아까 수정했던 `RPI_capture.py`와 `RPI_transfer.py` 파일을 순차적으로 실행합니다.
+
+```bash
+cd ~/SmartX-mini/IoT-labs
+
+chmod +x process.sh
+
+sudo ./process.sh
+```
+
+#### 2-5-3. IoT Web Service 접속하기 ( in NUC )
+
+NUC에서 웹브라우저를 열고 `http://<NUC IP>`에 접속해주세요.
+
+다음과 같은 화면을 확인한다면 성공입니다! 새로고침을 눌러, 온습도 센서 데이터가 지속적으로 바뀌는 것을 확인해보세요.
+
+<img width="490" alt="image" src="https://user-images.githubusercontent.com/63437430/161033216-2c5035de-e827-4f05-a095-f912c2772777.png">
+
+---
+
+## 3. Lab Summary
+
+이 Lab의 목표는 IoT 센서를 활용하여 데이터를 수집하고, 이를 서버에 전달하는 IoT-Cloud Hub를 구축하는 것입니다.
+여러분은 라즈베리파이를 활용하여 IoT 센서 데이터를 수집하고, 이를 NUC에 위치한 웹서버로 전송하여 시각화하는 IoT-Cloud 시스템을 구축하는 실습을 진행했습니다.
+
+### (Recall) IoT-Cloud 시스템이 왜 필요한가?
+
+IoT 기기에서 수집된 데이터는 개별적으로는 의미가 크지 않지만, 이를 클라우드에서 통합 및 분석하면 실시간 모니터링, 자동화, 원격 제어 등 다양한 분야에서 강력한 활용이 가능합니다. 이번 Lab에서는 IoT 데이터를 처리하고 웹에서 시각화하여, Tower Lab에서 다뤘던 모니터링 시스템과 유사한 IoT 기반 데이터 모니터링의 개념을 실습했습니다.
+
+### 주요 과정 요약
+
+1. 라즈베리파이 GPIO 핀을 활용하여 온습도 센서 연결 및 테스트
+2. 온습도 센서 데이터를 NUC 서버로 전송
+3. Node.js 기반의 웹 서버에서 데이터 시각화
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-gpio.png b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-gpio.png
new file mode 100644
index 0000000..aa3622a
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-gpio.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor-detail.png b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor-detail.png
new file mode 100644
index 0000000..e12cb77
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor-detail.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor.png b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor.png
new file mode 100644
index 0000000..a188933
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/img/pi-sensor.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/Lab#4_Tower_kr.md b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/Lab#4_Tower_kr.md
new file mode 100644
index 0000000..03e9bcc
--- /dev/null
+++ b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/Lab#4_Tower_kr.md	
@@ -0,0 +1,312 @@
+# Lab#4. Tower Lab
+
+## 0. Objective
+
+<img width="450" alt="overall objective" src="https://user-images.githubusercontent.com/82452337/160807997-9caadb51-b363-4e82-bbb2-e1f5888b08b3.png">
+
+**이번 Lab의 목표는 시스템을 모니터링하고 모니터링된 정보를 시각화할 수 있는 Tower(관제 시스템)을 구축하는 것입니다.**
+
+### 0-1. Lab Goal
+
+- 실시간 시스템 상태 모니터링
+- 대량의 시계열 데이터 저장 및 분석
+- 데이터 시각화를 통한 시스템 데이터의 직관적인 이해
+- Kafka 기반의 데이터 수집 → InfluxDB 저장 → Chronograf 시각화의 흐름
+
+지난 **Lab#2(InterConnect Lab)** 에서 구축한 Kafka 클러스터를 사용합니다.
+
+### 0-2. 모니터링 시스템이 왜 필요한가?
+
+시스템의 성능과 안정성을 유지하기 위해서는 실시간 모니터링이 필수적입니다. 시스템에서 발생한 장애를 신속하게 감지하고 대응할 수 있어야 하며, 시스템에서 발생한 시계열 데이터 분석을 통해 성능 최적화와 용량 계획을 수립할 수 있습니다. 특히, 분산 시스템에서는 다양한 노드에서 수집된 데이터를 종합적으로 분석해야 하므로, 이를 효과적으로 저장하고 시각화하는 시스템이 필요합니다. 이번 Lab에서는 Flume과 Kafka를 활용한 데이터 수집, InfluxDB를 통한 시계열 데이터 저장, 그리고 Chronograf를 이용한 데이터 시각화를 통해 모니터링 시스템 구축 방법을 익힙니다.
+
+### 0-3. TSDB (Time Series Database)
+
+#### Time Series Data의 시각화, 모니터링
+
+<img src="./img/time-series-data.png" alt="InfluxDB" width="450">
+
+시계열 데이터(Time Series Data)는 시간에 따라 변화하는 데이터를 저장하고 분석하는 방식으로, 각 데이터 포인트가 특정 시점의 값을 나타냅니다. 예를 들어, 서버의 CPU 사용률, 네트워크 트래픽, IoT 센서 데이터, 금융 시장 데이터 등이 시계열 데이터에 해당합니다. **Time Series Database**는 이러한 데이터를 효율적으로 저장하고 쿼리할 수 있도록 설계된 데이터베이스로, 빠른 조회, 실시간 분석, 장기적인 추세 파악에 최적화되어 있습니다.
+
+### 0-4. InfluxDB
+
+<img src="./img/influxdb.png" alt="InfluxDB" width="225">
+
+**InfluxDB**는 InfluxData에서 개발한 오픈소스 시계열 데이터베이스(TSDB)입니다.
+Go 프로그래밍 언어로 작성되었으며, 운영 모니터링, 애플리케이션 메트릭, 사물인터넷(IoT) 센서 데이터 및 실시간 분석과 같은 다양한 분야에서 시계열 데이터를 저장하고 검색하는 데 사용됩니다.
+
+### 0-5. Chronograf
+
+<img src="./img/chronograf-icon.png" alt="chronograf icon" width="225">
+
+#### InfluxDB, Chronograf를 사용한 간단한 모니터링 시스템 아키텍쳐
+
+<img src="./img/chronograf-arch.png" alt="chronograf comoponents" width="450">
+
+Chronograf는 InfluxDB 1.x 버전에서 사용되는 사용자 인터페이스(UI) 및 관리 컴포넌트입니다.
+Chronograf를 사용하면 InfluxDB에 저장된 데이터를 빠르게 확인하고, 쿼리 및 알림을 생성할 수 있습니다. 사용이 간편하며 여러 템플릿 및 라이브러리를 제공해 실시간 데이터를 시각화하는 대시보드를 빠르게 구축할 수 있습니다.
+
+## 1. Practice
+
+### 1-1. InfluxDB Container 생성 및 실행 ( in NUC )
+
+```bash
+sudo docker run -d --net host --name influxdb influxdb:1.7
+```
+
+이제 **InfluxDB**가 생성되었습니다. InfluxDB는 **8086번 port**를 사용하며, `--net host` option을 사용했기 때문에, InfluxDB에 접근하기 위해서는 `localhost:8086` 혹은 `<NUC IP>:8086`을 사용하게 됩니다.
+
+### 1-2. Chronograf Container 생성 및 실행 ( in NUC )
+
+InfluxDB에 접근할 수 있는 url을 argument로 입력해 **chronograf container**를 생성합니다.
+
+```bash
+sudo docker run -p 8888:8888 --name chronograf chronograf --influxdb-url http://<NUC IP>:8086
+```
+
+- **`-p 8888:8888`의 역할**
+
+  - host의 8888번 port를 container의 8888번 port과 mapping해줍니다.
+  - 즉, host의 8888번 port에 접근하면, container의 8888번 port로 forwarding됨을 의미합니다.
+  - 이 설정 덕분에, host에서 `localhost:8888`또는 `<NUC IP>:8888`로 접속하면 container 내부에서 실행 중인 Chronograf의 Web UI를 사용할 수 있게 됩니다.
+  - `-p <host port>:<container port>`로 사용됩니다!
+
+- **그럼 `--net host`와 `-p 8888:8888`의 주요 차이점은?**
+  - -p 8888:8888
+    - host의 ports 중 필요한 port(8888)만 노출되기 때문에, 보안적으로 더 안전하다고 볼 수 있습니다.
+    - 하지만, 매번 포트를 명시적으로 mapping 해줘야 합니다.
+  - --net host
+    - Container가 host의 네트워크를 그대로 사용합니다.
+    - 즉, container 내부에서 8888번 포트를 열면, host에서도 동일한 8888번 포트를 사용할 수 있습니다.
+    - 별도의 port mapping 설정이 필요하지 않습니다.
+
+아래 그림처럼 아무런 반응이 없는 상태가 지속된다면, 잘 실행된 것입니다.
+
+![chronograf_run.png](./img/chronograf_run.png)
+
+### 1-3. python-pip, python packages 설치하기 ( in NUC )
+
+이제 새로운 터미널을 열고 패키지 설치를 위해 아래 명령어를 터미널에서 실행합니다.
+
+#### 1-3-1. python-pip 설치
+
+> **Tip!** 새로운 터미널 열기 `Ctrl+Shift+t`
+
+```bash
+sudo apt-get install -y libcurl4 openssl curl python3-pip
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### NUC
+
+|   Package   |      Version       |
+| :---------: | :----------------: |
+|  libcurl4   | 7.68.0-1ubuntu2.15 |
+|   openssl   | 1.1.1f-1ubuntu2.16 |
+|    curl     | 7.68.0-1ubuntu2.15 |
+| python3-pip | 20.0.2-5ubuntu1.7  |
+
+</details>
+
+#### 1-3-2. Python Packages 설치
+
+```bash
+sudo pip install requests kafka-python influxdb msgpack
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### Python
+
+|   Package    | Version |
+| :----------: | :-----: |
+|   requests   | 2.22.0  |
+| kafka-python |  2.0.2  |
+|   influxdb   |  5.3.1  |
+|   msgpack    |  1.0.4  |
+
+</details>
+
+<br>
+
+### 1-4. Kafka Cluster 실행
+
+**지난 Lab2에서 사용했던 Kafka 클러스터**의 **zookeeper, broker0, broker1, broker2 containers**를 다시 실행하고, 각 container 역할별 프로그램을 실행합니다.
+
+#### 1-4-1. Kafka 클러스터 Containers 재실행
+
+아래 명령어를 입력해보면, 실행 종료된 zookeeper, brokers containers를 확인할 수 있습니다.
+
+```bash
+sudo docker ps -a
+```
+
+우리는 그 중에서 zookeeper, brokers containers를 다시 실행해야 합니다. 아래 명령어를 통해 해당 containers를 실행합니다.
+
+```bash
+sudo docker start zookeeper broker0 broker1 broker2
+```
+
+#### 1-4-2. Kafka Container 터미널 접속 및 프로그램 실행
+
+아래 명령어를 통해 각 docker container의 터미널에 접속할 수 있습니다. `zookeeper`, `broker0`, `broker1`, `broker2` 순서대로 접속하고, 각 container에 접속할 때마다 아래 Case에 해당하는 작업을 수행합니다.
+
+```bash
+sudo docker attach <docker container name>
+```
+
+##### Case 1: **`zookeeper` container인 경우**
+
+아래 명령어를 입력합니다. `bin/zookeeper-server.start.sh`는 zookeeper 서버를 실행하는 파일이며, `config/zookeeper.properties`는 Lab2에서 이미 수정했으므로 별도의 수정이 필요하지 않습니다.
+
+```bash
+bin/zookeeper-server-start.sh config/zookeeper.properties
+```
+
+##### Case 2: **`broker` container인 경우(broker0, broker1, broker2)**
+
+아래 명령어를 입력합니다. `bin/zookeeper-server.start.sh`는 broker 서버를 실행하는 파일이며, `config/server.properties`는 Lab2에서 이미 수정했으므로 별도의 수정이 필요하지 않습니다.
+
+```bash
+bin/kafka-server-start.sh config/server.properties
+```
+
+### 1-5. Flume container ( in PI )
+
+#### 1-5-1. `/etc/hosts`
+
+Pi가 reboot되면, 기존에 작성했던 /etc/hosts 정보가 사라질 수 있습니다. 그런 경우, /etc/hosts에 IP와 hostname 정보를 다시 입력해줘야 합니다.
+
+```bash
+sudo vim /etc/hosts
+```
+
+만약 기존에 작성했던 정보가 사라져있다면, 아래 2개의 lines을 추가하고 저장해주세요.
+
+> **주의**: [ ]는 본인에게 해당되는 정보로 교체해야함
+
+```
+[NUC_IP] [NUC_HOSTNAME]
+[PI_IP] [PI_HOSTNAME]
+```
+
+#### 1-5-2. Flume container 실행
+
+아래 명령어를 실행해 flume container을 실행하고, container 내부에 접근해주세요
+
+```bash
+# Execute Container
+sudo docker start flume
+# Access to Container
+sudo docker attach flume
+```
+
+Flume을 실행해주세요
+
+```bash
+bin/flume-ng agent --conf conf --conf-file conf/flume-conf.properties --name agent -Dflume.root.logger=INFO,console
+```
+
+### 1-6. Python File `broker_to_influxdb.py` ( in NUC )
+
+`broker_to_influxdb.py`는 kafka consumer로서 kafka broker로부터 message를 전달받고, influxdb에 해당 message data를 적재하는 역할을 합니다.
+
+#### 1-6-1. `broker_to_influxdb.py` 코드 수정
+
+```bash
+vi ~/SmartX-mini/ubuntu-kafkatodb/broker_to_influxdb.py
+```
+
+이 파일에서, `<NUC IP>`를 여러분의 실제 NUC IP로 수정해주세요.
+
+> e.g. `<NUC IP>`를 `203.237.53.100`로 수정
+
+<img width="650" alt="broker_to_influxdb python file" src="https://user-images.githubusercontent.com/82452337/160814546-da543a58-e6b6-49cb-bdb1-19aa2de9c1fb.png">
+
+#### 1-6-2. `broker_to_influxdb.py` 실행
+
+파일 디스크립터와 핸들에 대한 설정과 함께, `broker_to_influxdb.py`를 실행하는 아래 명령어를 입력해주세요.
+
+```bash
+sudo sysctl -w fs.file-max=100000
+ulimit -S -n 2048
+python3 ~/SmartX-mini/ubuntu-kafkatodb/broker_to_influxdb.py
+```
+
+### 1-7. Chronograf 대시보드 ( in NUC )
+
+#### 1-7-1. Chronograf 대시보드 접근하기
+
+웹 브라우저를 열고, Chronograf Dashboard에 접근하세요
+
+> **접근 주소**: http://\<Your NUC IP\>:8888
+
+<img src="./img/chronograf-1.png" alt="chronograf-1" width="450">
+
+### 1-7-1. 대시보드 생성하기
+
+<img src="./img/chronograf-2.png" alt="chronograf-2" width="450">
+
+### 1-7-2. 데이터 Source 추가하기
+
+<img src="./img/chronograf-3.png" alt="chronograf-3" width="450">
+
+### 1-7-3. 쿼리 등록하기
+
+<img src="./img/chronograf-4.png" alt="chronograf-4" width="450">
+
+```sql
+SELECT "memory" FROM "Labs"."autogen"."labs" WHERE time > :dashboardTime:
+```
+
+### 1-7-4. 모니터링 확인하기
+
+#### Memory 모니터링
+
+Memory의 현재 상태를 모니터링할 수 있습니다.
+
+<img src="./img/chronograf-5.png" alt="chronograf-5" width="450">
+
+#### CPU 모니터링
+
+CPU의 현재 상태를 모니터링할 수 있습니다.
+<img src="./img/chronograf-6.png" alt="chronograf-6" width="450">
+
+#### CPU 부하 테스트 ( in PI )
+
+모니터링 시스템이 데이터를 제대로 시각화하는지 확인하기 위해, CPU에 의도적인 부하를 줄 수 있습니다.
+
+우선, Chronograf Dashboard의 Fields를 `CPU_Usage`로 변경합니다
+
+<img src="./img/chronograf-6.png" alt="chronograf-6" width="450">
+
+그 다음, PI에서 다음의 명령어를 입력해보세요
+
+```bash
+docker run --rm -it busybox sh -c "while true; do :; done"
+```
+
+새로고침을 누르다보면 Dashboard의 그래프가 위로 움직이는 것을 확인할 수 있습니다. 확인했으면 `Ctrl + C`를 눌러 CPU 부하를 멈춰주세요.
+
+## 2. Lab Summary
+
+이 Lab의 목표는 시스템 모니터링 및 데이터 시각화를 위한 관제 시스템(Tower)을 구축하는 것입니다.
+이를 위해 Kafka 클러스터를 활용하여 수집한 데이터를 InfluxDB에 저장하고, Chronograf를 통해 시각화했습니다.
+
+### (Recall) Why this lab?
+
+- 실시간 시스템 상태 모니터링
+- 대량의 시계열 데이터 저장 및 분석
+- 데이터 시각화를 통한 시스템 데이터의 직관적인 이해
+- Kafka 기반의 데이터 수집 → InfluxDB 저장 → Chronograf 시각화의 흐름
+
+### 주요 과정 요약
+
+1. InfluxDB 컨테이너 실행 → 데이터를 저장하는 TSDB
+2. Chronograf 컨테이너 실행 → InfluxDB 데이터를 시각화하는 Web UI
+3. Kafka 클러스터 재시작 → 지난 Lab에서 구축한 Kafka를 다시 실행
+4. Flume 실행 → 데이터 스트리밍을 위한 Flume 에이전트 실행
+5. Python (Kafka) Consumer 실행 (broker_to_influxdb.py) → Kafka Broker로부터 데이터를 받아 InfluxDB에 적재
+6. Chronograf 대시보드 구성 → InfluxDB의 데이터를 시각적으로 확인할 수 있도록 설정
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-1.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-1.png
new file mode 100644
index 0000000..803c388
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-1.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-2.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-2.png
new file mode 100644
index 0000000..66bc30f
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-2.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-3.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-3.png
new file mode 100644
index 0000000..869b706
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-3.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-4.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-4.png
new file mode 100644
index 0000000..f0de49c
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-4.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-5.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-5.png
new file mode 100644
index 0000000..72e623a
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-5.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-6.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-6.png
new file mode 100644
index 0000000..abb2333
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-6.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-arch.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-arch.png
new file mode 100644
index 0000000..b8e0a2b
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-arch.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-icon.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-icon.png
new file mode 100644
index 0000000..d73ef13
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf-icon.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf.png
deleted file mode 100644
index fef61a9..0000000
Binary files a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf.png and /dev/null differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf_run.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf_run.png
new file mode 100644
index 0000000..51cb8fe
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/chronograf_run.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/influxdb.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/influxdb.png
new file mode 100644
index 0000000..ee10605
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/influxdb.png differ
diff --git a/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/time-series-data.png b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/time-series-data.png
new file mode 100644
index 0000000..b1c3a43
Binary files /dev/null and b/SmartX-Mini-2025 Collection/Experiment/Lab-4. Tower/img/time-series-data.png differ


Reviews:
user: login: tori209
body: 👍 💯 
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-11T09:09:45Z
user: login: GanghyeonSeo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T16:34:34Z
user: login: Kimcheolhui
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T16:45:46Z
user: login: GanghyeonSeo
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-11T17:11:06Z

Review comments:
diff_hunk: @@ -0,0 +1,301 @@
+# Lab#3. IoT Lab
+
+## 0. Objective
+
+<img width="916" alt="image" src="https://user-images.githubusercontent.com/63437430/161034315-b201ae9e-463e-44d3-a02f-4796a90f6ee4.png">
+
+**이번 Lab의 목표는 IoT 센서를 활용하여 데이터를 수집하고, 이를 서버에 전달하는 IoT-Cloud Hub를 구축하는 것입니다.**
+
+### 0-1. Lab Goal
+
+- 라즈베리파이를 이용한 IoT 센서 데이터 수집
+- 센서 데이터를 클라우드 서버로 전송
+- Node.js 기반의 웹 서버를 통해 실시간 데이터 시각화
+
+이번 Lab에서는 라즈베리파이(Raspberry Pi) 를 사용하여 센서 데이터를 수집하고, 이를 NUC 서버에서 처리하여 시각화하는 과정을 실습합니다.
+
+### 0-2. IoT-Cloud 시스템이 왜 필요한가?
+
+IoT 기기에서 수집되는 데이터는 개별적으로는 의미가 크지 않지만, 이를 클라우드에서 통합 및 분석하면 강력한 정보나 인사이트를 얻을 수 있습니다. 이러한 데이터는 실시간 모니터링, 자동화, 원격 제어 등의 다양한 분야에서 활용됩니다. Tower Lab에서 진행한 모니터링 시스템 구축과 그 필요성이 비슷하며, 이 Lab에서는 IoT를 활용한 모니터링 시스템이라고 볼 수 있습니다.
+
+### 0-3. Node.js
+
+Node.js는 오픈 소스, 크로스 플랫폼을 지원하는 백엔드 JavaScript 런타임 환경으로, V8 엔진에서 실행되며 웹 브라우저 외부에서도 JavaScript 코드를 실행할 수 있습니다. Node.js를 사용하면 개발자가 JavaScript로 명령줄 도구(Command Line Tool)를 작성하거나, 서버 측 스크립트(Server-Side Scripting)를 실행하여 웹 페이지가 사용자에게 전송되기 전에 동적으로 콘텐츠를 생성할 수 있습니다. 결과적으로, Node.js는 "JavaScript everywhere" 패러다임을 실현하여, 서버와 클라이언트에서 각각 다른 언어를 사용할 필요 없이 단일 프로그래밍 언어(JavaScript)로 웹 애플리케이션을 개발할 수 있도록 해줍니다. 이번 Lab에서는 IoT 센서 데이터를 저장하고 간단한 시각화를 위해 Node.js를 사용합니다.
+
+### 0-4. Adafruit_python_DHT
+
+온습도 센서를 손쉽게 사용하기 위해 Adafruit_python_DHT를 사용합니다. Adafruit_python_DHT는 Adafruit에서 제공하는 Python 라이브러리로, DHT11, DHT22, AM2302 등의 온습도 센서를 Raspberry Pi 및 BeagleBone과 같은 SBC(Single Board Computer)에서 쉽게 사용할 수 있도록 지원합니다. 이 라이브러리는 센서 데이터를 읽고 처리하는 기능을 제공하며, 간단한 Python 코드로 온도 및 습도를 측정할 수 있습니다.
+
+## 1. Preparation
+
+<img src="img/pi-gpio.png" alt="pi gpio" width="450">
+
+위 이미지는 라즈베리파이의 **GPIO(General Purpose Input/Output, 범용 입출력) 핀 배치도**를 나타냅니다. GPIO는 라즈베리파이에서 외부 장치와 연결하여 전기 신호를 주고 받을 수 있는 핀입니다. 간단히 말해, 센서, LED, 모터 등 다양한 기기를 연결하여 입력을 받거나 출력을 보낼 수 있는 다목적 핀이라고 볼 수 있습니다.
+
+- 빨간색 핀(3.3V 전원): 이 핀은 3.3V 전원을 출력하며, 저전력 센서 및 기타 주변 장치에 안정적인 전압을 공급하는 데 사용됩니다.
+- 노란색 핀(GPIO4): 일반적인 GPIO 핀으로, 다양한 입력 및 출력 역할을 수행할 수 있습니다.
+- 검은색 핀(GND): 전자의 흐름이 돌아오는 길(기준점) 역할을 합니다. 센서나 LED를 연결할 때 전원(여기서는 3.3V)과 함께 항상 필요한 핀입니다.
+
+> **이제 위 사진의 빨간색 상자 내부처럼 라즈베리파이에 온습도 센서를 연결해줍니다. 실물 사진은 아래를 참고해주세요!**
+
+<img src="img/pi-sensor.png" alt="pi with sensor" width="450">
+
+<img src="img/pi-sensor-detail.png" alt="pi with sensor" width="450">
+
+---
+
+## 2. Practice
+
+### 2-1. Node.js 웹 서버를 위한 Docker Container 실행 ( in NUC )
+
+#### 2-1-1. Docker Container 실행
+
+아래의 준비된 도커 컨테이너 이미지를 띄워주세요.
+
+(\*연구실에서 수정 작업을 했기 때문에 저 dns가 꼭 필요한지 확인하지 못했으나, 마지막 확인 작업 때 dns 없이도 잘 돌아가는지 확인하고 삭제할 것)
+
+```bash
+sudo docker run -it --net host --dns 203.237.32.100 --name webserver cheolhuikim/smartx-box-mini
+```
+
+컨테이너 내부에 진입하면 아래 명령어를 실행해주세요.
+
+```bash
+apt-get update
+
+apt-get install vim
+```
+
+### 2-2. 웹 서버 코드 수정하기 (NUC)
+
+아래 명령어를 입력해 웹 서버 코드를 확인하고, `<NUC IP>`를 여러분의 NUC IP로 수정해주세요.
+
+```bash
+vi /SmartX-Mini/IoT-labs/webserver.js
+```
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160828580-7201f53f-e66a-40d3-8682-ca237476b20a.png">
+
+### 2-3. 온습도 센서 테스트 ( in PI )
+
+이제 라즈베리파이에 연결된 온습도 센서가 제대로 동작하는지 확인하겠습니다.
+
+#### 2-3-1. Install package
+
+아래 명령어를 입력해 필요한 파일들을 다운로드 해주세요
+
+```bash
+git clone https://github.com/adafruit/Adafruit_python_DHT.git
+```
+
+> **Adafruit_python_DHT?** `0-4. Adafruit_python_DHT` 참고
+
+라즈베리파이 버전 4를 3으로 인식할 수 있도록 Adafruit_DHT의 패키지 Installer를 수정해줘야합니다.
+
+> **Why?** 라즈베리파이 4의 SoC(System on Chip)는 BCM2711이지만, 기존 Adafruit_python_DHT 라이브러리는 이를 인식하지 못하고 기본적으로 지원하는 BCM2835, BCM2837 등과 다르게 처리합니다. 따라서, platform_detect.py 파일에서 BCM2711을 Pi 3으로 인식하도록 설정하면 라이브러리가 정상적으로 작동하며, 추가적인 호환성 문제 없이 센서 데이터를 읽을 수 있습니다.
+
+우선, 파일을 열어줍니다
+
+```bash
+cd Adafruit_python_DHT
+
+sudo vi Adafruit_DHT/platform_detect.py
+```
+
+**BCM2711**에 대한 case를 `pi_version` 함수에 추가해주고, 3을 return하도록 합니다.
+
+```python
+def pi_version():
+    …
+    elif match.group(1) == 'BCM2835':
+        # Pi 3 or Pi 4
+        return 3
+    elif match.group(1) == 'BCM2837':
+        # Pi 3b+
+        return 3
+    elif match.group(1) == 'BCM2711': # 추가
+        # Pi 4b
+        return 3                      # 추가
+    else:
+        # Something else, not a pi.
+        return None
+
+```
+
+패키지 Installer를 수정했으므로, 이제 필요한 패키지들을 설치해줍니다. 약간 시간이 걸릴 수 있습니다.
+
+```bash
+
+sudo apt-get update
+
+sudo apt-get install python3-pip
+
+sudo python3 -m pip install --upgrade pip setuptools wheel
+
+sudo apt install -y build-essential python3-dev
+
+sudo pip3 install .
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|     Package     |   Version   |
+| :-------------: | :---------: |
+|   python3-pip   | 18.1-5+rpt1 |
+| build-essential |    12.6     |
+|   python3-dev   |   3.7.3-1   |
+
+##### Python
+
+|  Package   |   Version   |
+| :--------: | :---------: |
+| setuptools |  40.8.0-1   |
+|   wheel    | 18.1-5+rpt1 |
+
+</details>
+<br>
+
+#### 2-3-2. 온습도 센서 테스트 ( in PI )
+
+예제 폴더로 이동합니다.
+
+```bash
+cd ~/Adafruit_python_DHT/examples
+```
+
+테스트 코드를 열고, `python`을 `python3`로 수정합니다
+
+```bash
+sudo vi AdafruitDHT.py
+```
+
+From
+
+```python
+#!/usr/bin/python
+...
+
+```
+
+To
+
+```python
+#!/usr/bin/python3
+...
+
+```
+
+테스트 코드를 실행합니다.
+
+```bash
+sudo ./AdafruitDHT.py 11 4
+```
+
+아래와 같이 온도와 습도가 잘 표기됐다면, 온습도 센서가 라즈베리파이에 제대로 연결된 것을 의미합니다. 만약 오류가 발생한다면, 아래 순서를 따라주세요.
+
+1. `1. Preparation`으로 돌아가서 온습도 센서의 핀이 올바른 GPIO 핀에 꽂혀있는지 확인해주세요.
+2. 아무런 문제를 발견하지 못했다면, 패키지 설치가 제대로 됐는지 확인해주세요. 패키지를 다시 설치해보는 것도 방법이 될 수 있습니다.
+3. 센서 자체의 문제일 수 있습니다. 만약 여전히 문제가 해결되지 않았다면, 조교를 호출해주세요.
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160829118-04bae048-2cf3-4c3f-8cd9-4b9295b019d0.png">
+
+### 2-4. 센서 데이터 수집과 전송 ( in PI )
+
+이번에는 라즈베리파이에서 수집한 센서 데이터를 NUC으로 전달하기 위해, 관련 코드를 수정하겠습니다.
+
+#### 2-4-1. 필요한 패키지 설치
+
+```bash
+sudo apt-get update
+
+sudo apt-get install python3-numpy
+
+sudo apt-get install mercurial
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|    Package    |     Version     |
+| :-----------: | :-------------: |
+| python3-numpy |   1:1.16.2-1    |
+|   mercurial   | 4.8.2-1+deb10u1 |
+
+</details>
+<br>
+
+#### 2-4-2. 센서 데이터 수집 코드
+
+센서 데이터 수집 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_capture.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829267-f2198912-a27d-4ee3-9b44-e5af753aff6d.png">
+
+#### 2-4-3. 센서 데이터 전송 코드
+
+센서 데이터 전송 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_transfer.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829383-8053b56c-a4ea-42d1-b4d1-220502b7754a.png">
+
+### 2-5. IoT Web Service 실행하기
+
+이제 지금까지 작업한 내용을 바탕으로 간단한 IoT Web Service를 실행하도록 하겠습니다.
+
+#### 2-5-1. Web Server 실행하기 ( in NUC )
+
+아까 NUC 실행했던 도커 컨테이너 내부에서 다음의 명령어를 실행해주세요. 다음의 명령어는 `webserver.js`라는 웹서버 코드를 실행합니다.
path: SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/Lab#3_IoT_kr.md
user: login: GanghyeonSeo
body: "아까 NUC 실행했던" -> 이 부분을 수정해야할 것 같습니다.
created_at: 2025-03-11T16:34:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,301 @@
+# Lab#3. IoT Lab
+
+## 0. Objective
+
+<img width="916" alt="image" src="https://user-images.githubusercontent.com/63437430/161034315-b201ae9e-463e-44d3-a02f-4796a90f6ee4.png">
+
+**이번 Lab의 목표는 IoT 센서를 활용하여 데이터를 수집하고, 이를 서버에 전달하는 IoT-Cloud Hub를 구축하는 것입니다.**
+
+### 0-1. Lab Goal
+
+- 라즈베리파이를 이용한 IoT 센서 데이터 수집
+- 센서 데이터를 클라우드 서버로 전송
+- Node.js 기반의 웹 서버를 통해 실시간 데이터 시각화
+
+이번 Lab에서는 라즈베리파이(Raspberry Pi) 를 사용하여 센서 데이터를 수집하고, 이를 NUC 서버에서 처리하여 시각화하는 과정을 실습합니다.
+
+### 0-2. IoT-Cloud 시스템이 왜 필요한가?
+
+IoT 기기에서 수집되는 데이터는 개별적으로는 의미가 크지 않지만, 이를 클라우드에서 통합 및 분석하면 강력한 정보나 인사이트를 얻을 수 있습니다. 이러한 데이터는 실시간 모니터링, 자동화, 원격 제어 등의 다양한 분야에서 활용됩니다. Tower Lab에서 진행한 모니터링 시스템 구축과 그 필요성이 비슷하며, 이 Lab에서는 IoT를 활용한 모니터링 시스템이라고 볼 수 있습니다.
+
+### 0-3. Node.js
+
+Node.js는 오픈 소스, 크로스 플랫폼을 지원하는 백엔드 JavaScript 런타임 환경으로, V8 엔진에서 실행되며 웹 브라우저 외부에서도 JavaScript 코드를 실행할 수 있습니다. Node.js를 사용하면 개발자가 JavaScript로 명령줄 도구(Command Line Tool)를 작성하거나, 서버 측 스크립트(Server-Side Scripting)를 실행하여 웹 페이지가 사용자에게 전송되기 전에 동적으로 콘텐츠를 생성할 수 있습니다. 결과적으로, Node.js는 "JavaScript everywhere" 패러다임을 실현하여, 서버와 클라이언트에서 각각 다른 언어를 사용할 필요 없이 단일 프로그래밍 언어(JavaScript)로 웹 애플리케이션을 개발할 수 있도록 해줍니다. 이번 Lab에서는 IoT 센서 데이터를 저장하고 간단한 시각화를 위해 Node.js를 사용합니다.
+
+### 0-4. Adafruit_python_DHT
+
+온습도 센서를 손쉽게 사용하기 위해 Adafruit_python_DHT를 사용합니다. Adafruit_python_DHT는 Adafruit에서 제공하는 Python 라이브러리로, DHT11, DHT22, AM2302 등의 온습도 센서를 Raspberry Pi 및 BeagleBone과 같은 SBC(Single Board Computer)에서 쉽게 사용할 수 있도록 지원합니다. 이 라이브러리는 센서 데이터를 읽고 처리하는 기능을 제공하며, 간단한 Python 코드로 온도 및 습도를 측정할 수 있습니다.
+
+## 1. Preparation
+
+<img src="img/pi-gpio.png" alt="pi gpio" width="450">
+
+위 이미지는 라즈베리파이의 **GPIO(General Purpose Input/Output, 범용 입출력) 핀 배치도**를 나타냅니다. GPIO는 라즈베리파이에서 외부 장치와 연결하여 전기 신호를 주고 받을 수 있는 핀입니다. 간단히 말해, 센서, LED, 모터 등 다양한 기기를 연결하여 입력을 받거나 출력을 보낼 수 있는 다목적 핀이라고 볼 수 있습니다.
+
+- 빨간색 핀(3.3V 전원): 이 핀은 3.3V 전원을 출력하며, 저전력 센서 및 기타 주변 장치에 안정적인 전압을 공급하는 데 사용됩니다.
+- 노란색 핀(GPIO4): 일반적인 GPIO 핀으로, 다양한 입력 및 출력 역할을 수행할 수 있습니다.
+- 검은색 핀(GND): 전자의 흐름이 돌아오는 길(기준점) 역할을 합니다. 센서나 LED를 연결할 때 전원(여기서는 3.3V)과 함께 항상 필요한 핀입니다.
+
+> **이제 위 사진의 빨간색 상자 내부처럼 라즈베리파이에 온습도 센서를 연결해줍니다. 실물 사진은 아래를 참고해주세요!**
+
+<img src="img/pi-sensor.png" alt="pi with sensor" width="450">
+
+<img src="img/pi-sensor-detail.png" alt="pi with sensor" width="450">
+
+---
+
+## 2. Practice
+
+### 2-1. Node.js 웹 서버를 위한 Docker Container 실행 ( in NUC )
+
+#### 2-1-1. Docker Container 실행
+
+아래의 준비된 도커 컨테이너 이미지를 띄워주세요.
+
+(\*연구실에서 수정 작업을 했기 때문에 저 dns가 꼭 필요한지 확인하지 못했으나, 마지막 확인 작업 때 dns 없이도 잘 돌아가는지 확인하고 삭제할 것)
+
+```bash
+sudo docker run -it --net host --dns 203.237.32.100 --name webserver cheolhuikim/smartx-box-mini
+```
+
+컨테이너 내부에 진입하면 아래 명령어를 실행해주세요.
+
+```bash
+apt-get update
+
+apt-get install vim
+```
+
+### 2-2. 웹 서버 코드 수정하기 (NUC)
+
+아래 명령어를 입력해 웹 서버 코드를 확인하고, `<NUC IP>`를 여러분의 NUC IP로 수정해주세요.
+
+```bash
+vi /SmartX-Mini/IoT-labs/webserver.js
+```
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160828580-7201f53f-e66a-40d3-8682-ca237476b20a.png">
+
+### 2-3. 온습도 센서 테스트 ( in PI )
+
+이제 라즈베리파이에 연결된 온습도 센서가 제대로 동작하는지 확인하겠습니다.
+
+#### 2-3-1. Install package
+
+아래 명령어를 입력해 필요한 파일들을 다운로드 해주세요
+
+```bash
+git clone https://github.com/adafruit/Adafruit_python_DHT.git
+```
+
+> **Adafruit_python_DHT?** `0-4. Adafruit_python_DHT` 참고
+
+라즈베리파이 버전 4를 3으로 인식할 수 있도록 Adafruit_DHT의 패키지 Installer를 수정해줘야합니다.
+
+> **Why?** 라즈베리파이 4의 SoC(System on Chip)는 BCM2711이지만, 기존 Adafruit_python_DHT 라이브러리는 이를 인식하지 못하고 기본적으로 지원하는 BCM2835, BCM2837 등과 다르게 처리합니다. 따라서, platform_detect.py 파일에서 BCM2711을 Pi 3으로 인식하도록 설정하면 라이브러리가 정상적으로 작동하며, 추가적인 호환성 문제 없이 센서 데이터를 읽을 수 있습니다.
+
+우선, 파일을 열어줍니다
+
+```bash
+cd Adafruit_python_DHT
+
+sudo vi Adafruit_DHT/platform_detect.py
+```
+
+**BCM2711**에 대한 case를 `pi_version` 함수에 추가해주고, 3을 return하도록 합니다.
+
+```python
+def pi_version():
+    …
+    elif match.group(1) == 'BCM2835':
+        # Pi 3 or Pi 4
+        return 3
+    elif match.group(1) == 'BCM2837':
+        # Pi 3b+
+        return 3
+    elif match.group(1) == 'BCM2711': # 추가
+        # Pi 4b
+        return 3                      # 추가
+    else:
+        # Something else, not a pi.
+        return None
+
+```
+
+패키지 Installer를 수정했으므로, 이제 필요한 패키지들을 설치해줍니다. 약간 시간이 걸릴 수 있습니다.
+
+```bash
+
+sudo apt-get update
+
+sudo apt-get install python3-pip
+
+sudo python3 -m pip install --upgrade pip setuptools wheel
+
+sudo apt install -y build-essential python3-dev
+
+sudo pip3 install .
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|     Package     |   Version   |
+| :-------------: | :---------: |
+|   python3-pip   | 18.1-5+rpt1 |
+| build-essential |    12.6     |
+|   python3-dev   |   3.7.3-1   |
+
+##### Python
+
+|  Package   |   Version   |
+| :--------: | :---------: |
+| setuptools |  40.8.0-1   |
+|   wheel    | 18.1-5+rpt1 |
+
+</details>
+<br>
+
+#### 2-3-2. 온습도 센서 테스트 ( in PI )
+
+예제 폴더로 이동합니다.
+
+```bash
+cd ~/Adafruit_python_DHT/examples
+```
+
+테스트 코드를 열고, `python`을 `python3`로 수정합니다
+
+```bash
+sudo vi AdafruitDHT.py
+```
+
+From
+
+```python
+#!/usr/bin/python
+...
+
+```
+
+To
+
+```python
+#!/usr/bin/python3
+...
+
+```
+
+테스트 코드를 실행합니다.
+
+```bash
+sudo ./AdafruitDHT.py 11 4
+```
+
+아래와 같이 온도와 습도가 잘 표기됐다면, 온습도 센서가 라즈베리파이에 제대로 연결된 것을 의미합니다. 만약 오류가 발생한다면, 아래 순서를 따라주세요.
+
+1. `1. Preparation`으로 돌아가서 온습도 센서의 핀이 올바른 GPIO 핀에 꽂혀있는지 확인해주세요.
+2. 아무런 문제를 발견하지 못했다면, 패키지 설치가 제대로 됐는지 확인해주세요. 패키지를 다시 설치해보는 것도 방법이 될 수 있습니다.
+3. 센서 자체의 문제일 수 있습니다. 만약 여전히 문제가 해결되지 않았다면, 조교를 호출해주세요.
+
+<img width="450" alt="image" src="https://user-images.githubusercontent.com/63437430/160829118-04bae048-2cf3-4c3f-8cd9-4b9295b019d0.png">
+
+### 2-4. 센서 데이터 수집과 전송 ( in PI )
+
+이번에는 라즈베리파이에서 수집한 센서 데이터를 NUC으로 전달하기 위해, 관련 코드를 수정하겠습니다.
+
+#### 2-4-1. 필요한 패키지 설치
+
+```bash
+sudo apt-get update
+
+sudo apt-get install python3-numpy
+
+sudo apt-get install mercurial
+```
+
+<details>
+<summary>Package Versions (Expand)</summary>
+
+##### PI
+
+|    Package    |     Version     |
+| :-----------: | :-------------: |
+| python3-numpy |   1:1.16.2-1    |
+|   mercurial   | 4.8.2-1+deb10u1 |
+
+</details>
+<br>
+
+#### 2-4-2. 센서 데이터 수집 코드
+
+센서 데이터 수집 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_capture.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829267-f2198912-a27d-4ee3-9b44-e5af753aff6d.png">
+
+#### 2-4-3. 센서 데이터 전송 코드
+
+센서 데이터 전송 코드를 열고, `<NUC IP>`를 여러분의 NUC IP로 수정합니다.
+
+```bash
+vi ~/SmartX-mini/IoT-labs/RPI_transfer.py
+```
+
+<img width="500" alt="image" src="https://user-images.githubusercontent.com/63437430/160829383-8053b56c-a4ea-42d1-b4d1-220502b7754a.png">
+
+### 2-5. IoT Web Service 실행하기
+
+이제 지금까지 작업한 내용을 바탕으로 간단한 IoT Web Service를 실행하도록 하겠습니다.
+
+#### 2-5-1. Web Server 실행하기 ( in NUC )
+
+아까 NUC 실행했던 도커 컨테이너 내부에서 다음의 명령어를 실행해주세요. 다음의 명령어는 `webserver.js`라는 웹서버 코드를 실행합니다.
path: SmartX-Mini-2025 Collection/Experiment/Lab-3. IoT/Lab#3_IoT_kr.md
user: login: Kimcheolhui
body: > "아까 NUC 실행했던" -> 이 부분을 수정해야할 것 같습니다.

해당 내용 반영했습니다.
[#023b370](https://github.com/SmartX-Labs/SmartX-Mini/pull/76/commits/023b370c0957fc8092fcbfd4b0da5af14609b45c)
created_at: 2025-03-11T16:45:46Z
author_association: COLLABORATOR

PR comments:
user: login: tori209
created_at: 2025-03-11T05:19:15Z
body: node.js Docker 이미지 아키텍처 차이로 Pi에서 안돌아갑니다! (Image: amd64 / Pi: arm)
author_association: COLLABORATOR
user: login: Kimcheolhui
created_at: 2025-03-11T05:58:27Z
body: > node.js Docker 이미지 아키텍처 차이로 Pi에서 안돌아갑니다! (Image: amd64 / Pi: arm)

node.js Docker 이미지는 Pi에서 실행하지 않기 때문에 별도로 지원하지 않습니다!
다만, 추후 NUC 대신 Pi를 webserver로 사용할 수 있기 때문에, `buildx`를 사용해 `linux/arm64`, `linux/arm/v7`(pi)를 추가로 지원하도록 docker image를 재빌드해서 docker hub에 올려두었습니다.
author_association: COLLABORATOR