본문 바로가기
컴퓨터 & IT (Computer & IT)/Raspberry pi 3

[Rasberry pi] 라즈베리 파이를 이용한 서버실 온도 체크

by Physics 2021. 7. 28.
728x90

문제 상황 1: 현재 우리 연구실에서 사용하는 클러스터가 있는 서버실의 온도를 측정할 필요가 있다. 여기서 서버실의 온도를 측정할 때, 우리가 원하는 조건은 아래와 같다.
====================================================================
    (1) 서버실의 온도를 일정한 시간 간격으로 측정하고자 한다. (예를 들면, 5분 간격으로 온도를 측정) 
    (2) 측정한 서버실의 온도를 인터넷 웹 브라우저로 확인하고자 한다. 
        - 이때, 그래프 (시간 vs 온도)로 시각적으로 확인 
    (3) 약 2 주정도의 데이터만 보유하고 나머지 이전 데이터들은 자동으로 폐기하도록 한다. 
    (4) 만일 서버실 온도가 특정 온도 이상이 되면 경고 메일을 자동으로 보내도록 한다. 
====================================================================

문제 상황 2: 현재 우리가 사용하는 클러스터의 계산 노드들의 CPU온도를 위 서버실의 온도와 마찬가지로 자동으로 측정 및 시각화하도록 한다.


1. 서버실 온도 측정 

1) 준비물: 아두이노용 습온도계 센서 (DHT11 또는 DHT22), 라즈베리 파이, 리눅스 컴퓨터 
※ 가정 1: 라즈베리 파이와 데스크탑 컴퓨터(마스터 서버)는 서로 내부망으로 연결되어있다고 가정함 
※ 가정 2: 라즈베리 파이는 데스크탑 컴퓨터로부터 masquerade를 통해 외부 인터넷 망으로부터 데이터를 송수신 받을 수 있음 

서버실 온도의 경우, 일반 데스크탑에서 온도계 센서를 연결 후 직접적으로 측정하는 방법을 인터넷에서 찾지 못하였다. 따라서, 라즈베리 파이를 이용하는 방법으로 진행하였다. 우선, 라즈베리 파이와 온도계 센서를 연결하고, 라즈베리 파이와 클러스터의 마스터 서버는 내부망으로 연결이 되어있고, 서로 ssh를 통해서 서로 데이터를 주고 받도록 하였다. 대략적인 상황은 아래와 같다. 

 

 

2) 라즈베리 파이와 온도계 센서 (DHT 22) 연결

위의 그림과 같이, 라즈베리 파이의 GPIO 핀과 DHT22를 연결한다. 
  • DHT22의 DAT 부분을 라즈베리 파이의 GPIO의 3번 핀(GPIO 2)과 연결 
  • DHT22의 VCC 부분을 라즈베리 파이의 GPIO의 2번 핀(5V power)에 연결 
  • DHT22의 GND 부분을 라즈베리 파이의 GPIO 9 번 핀 (Ground)에 연결

 

3) DHT 22를 작동하기 위한 파일 설치

라즈베리 파이의 pi 계정*에 접속 후, github을 통해 DHT 22를 작동하기 위한 프로그램을 다운받도록 하자. 
* 라즈베리 파이의 default 계정 

$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git

이후, Adafruit_Python_DHT란 디렉토리가 생성이 된다. 다음으로는 해당 디렉토리에 들어간 후, setup 파일을 아래와 같이 실행하자. 

$ cd Adafruit_Python_DHT
$ python setup.py install

 

이후, examples란 디렉토리로 들어간 후, AdafuitDHT.py를 다음과 같이 수정한다. 

$ vim AdafruitDHT.py
...
<수정 전>
if humidity is not None and temperature is not None:
	print('Temp={0:0.1f}* Humidity={1:0.1f}%'.format(temperature, humidity))
    
<수정 후>
if humidity is not None and temperature is not None:
	print('{0:0.1f} {1:0.1f}'.format(temperature, humidity))

...

 

이후, 아래 명령어로 해당 파일을 실행시키면, 측정한 온도와 습도가 화면에 출력된다. 

$ ./AdafruitDHT.py 22 2
30.9  56.1

※ 위 숫자 22의 의미는 DHT22 센서를 의미한다. 
※ 마지막 숫자 2는 DHT 22 센서로부터 GPIO 2로부터 데이터를 받는 것을 의미한다. 

4) 측정 온도 저장

(a) 마스터 서버와 라즈베리 파이 간 데이터 송수신
라즈베리 파이에서 측정한 온도는 서버에서 ssh 통신을 통해 서버로 받을 수 있다. 서버에서 다음 명령어를 입력했을 때, 라즈베리 파이에서 측정한 온도를 송수신하는지 확인해보자. 정상적으로 연결이 되어있다면, 아래와 같이 데이터들이 터미널 화면에 뜨게 된다. 

$ssh pi@192.168.0.254 python /home/pi/Adafruit_Python_DHT/examples/AdafruitDHT.py 22 2
30.7 56.3

※ 192.168.0.254: 라즈베리 파이의 내부망 IP 주소 

(b) 데이터 베이스 세팅  
위와 같이 측정한 데이터들을 저장하기 위해 mysql이란 Database를 사용한다. 우선, 마스터 서버에 mysql이 설치되어있다고 가정하도록 하겠다. mysql의 root계정으로 아래와 같이 데이터 베이스 세팅을 한다. 

  • 데이터들을 저장하기 위한 mysql 사용자 생성 (temp_monitor)

$ mysql -u root -p 
Enter password: <password 기입>

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 48215
Server version: 8.0.25 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE USER temp_monitor

 

  • 측정할 데이터들이 저장하게 될 데이터 베이스 생성 (데이터 베이스 이름: TEMPERATURE)

mysql> CREATE DATABASE TEMPERATURE

 

  • 데이터들이 실제 저장될 테이블 생성 ( 이름: server_room) 

mysql> CREATE TABLE server_room (      
    id INT NOT NULL AUTO_INCREMENT,      
    date date,  
    time time,  
    temperature double,  
    humidity double,      
    PRIMARY KEY (id)
 );

 

   • temp_monitor 계정에 아래와 같은 권한을 TEMPERATURE DB 내에 부여

mysql> GRANT INSERT, SELECT, DELETE, UPDATE, ALTER, DROP ON TEMPERATURE.* TO 'temp_monitor';

 

(c) 라즈베리 파이에서 수신 받은 데이터들을 DB에 저장 
이후, 라즈베리 파이에서 수신 받은 데이터들을 DB에 저장하기 위해서, 아래와 같이 Shell script를 이용하여 프로그램을 작성한다. 

$ vim temp_shell.sh
#! /bin/bash

DIR="$( cd "$( dirname "$0" )" && pwd -P )"
date=`date "+%Y-%m-%d %H:%M:%S"`
days=$( echo $date | awk '{print $1}')
time=$( echo $date | awk '{print $2}')

########################################################################################
#   1. CHECKING TEMPERATURE AND HUMIDITY IN SERVER ROOM
#---------------------------------------------------------------------------------------
# By using a sensor connected with Raspberry Pi, we send to Rasberry Pi a commend for
# detecting temperature and humidity in server room. Received data are stored in MySQL.
########################################################################################

expect<<EOF > $DIR/dummy_data.txt
set timeout -1
spawn ssh pi@192.168.0.254 python /home/pi/Adafruit_Python_DHT/examples/AdafruitDHT.py 22 2
expect -re "password"
send "라즈베리 파이의 pi 계정의 비밀번호 입력\r"
expect eof
EOF

data=$( tail -1 $DIR/dummy_data.txt )
server_temp=$( echo $data | awk '{print $1}' )
server_humd=$( echo $data | awk '{print $2}' )

rm $DIR/dummy_data.txt

mysql -u temp_monitor TEMPERATURE <<EOF
    insert into server_room (date, time, temperature, humidity) values ("$days", "$time", $server_temp, $server_humd);
EOF

threshold_temp=40.0
IsItSafe=$(echo "$server_temp, $threshold_temp" | awk '{ i = $2 - $1; if (i < 0) print 1; else print -1;}' )

if [ $IsItSafe -eq 1 ]; then
    cat << EOF > Alert_mail.txt
===SERVER ROOM INFORMATION ===
At $date, the temperature of the server room, $server_temp, is 
above threshold temperature, $threshold_temp (Celsius Degree).
EOF
    cat Alert_mail.txt | mail -s "Temperature Alert Report" <메일 주소>

fi

python3 $DIR/today_temp.py

  NOTE 1: ssh를 통해 라즈베리 파이로 명령어를 보낼 시, shell script를 실행할 때마다 비밀번호를 매번 입력하지 않도록 expect 명령어를 이용함. 라즈베리 파이의 pi 계정에 대응되는 비밀번호를 위에 입력하면 됨
  NOTE 2: 라즈베리 파이에서 받은 데이터 (온도 및 습도)를 dummy_data.txt 에 저장 후, 마지막 열 (온도와 습도)을 변수 data에 저장후, dummy_data.txt를 삭제함. awk를 이용하여 변수 data로부터 온도와 습도를 각각 server_temp와 server_humd에 저장함. 
  NOTE 3: mysql 명령문을 통해서 측정 날짜, 시간, 측정 온도, 측정 습도를 MySQL DB에 저장함. 
  NOTE 4: 만일, 서버실의 온도가 지정해 놓은 온도 (threshold_temp) 이상일 경우에 경고 메일을 보내도록 함. 
  NOTE 5: 위에서 저장한 DB로부터 시간 vs 온도에 대한 그래프를 파이썬을 이용하여 그래프를 생성하고 저장함 (today_temp.py)

(d) 매 5분마다 온도를 측정하도록 crontab 설정 

$ crontab -e 
...
*/5 *   *   *   *   /var/www/html/temp_monitor/temp_shell.sh

매 5분마다 측정을 하기 위해, crontab에 위와 같이 추가한다.

만약 정상적으로 작동한다면, 다음 명령어를 마스터 서버의 터미널에 입력했을 때, 아래와 같이 출력된다. 

cmt323@master:~$ mysql -u temp_monitor CMT_TEMPERATURE -e "select * from SERVER_ROOM";
+-----+------------+----------+-------------+----------+
| id  | date       | time     | temperature | humidity |
+-----+------------+----------+-------------+----------+
|   1 | 2021-07-31 | 02:55:01 |        35.6 |     38.4 |
|   2 | 2021-07-31 | 03:00:01 |          36 |     37.7 |
|   3 | 2021-07-31 | 03:05:01 |        36.5 |     36.8 |
|   4 | 2021-07-31 | 03:10:01 |        36.4 |     36.8 |
|   5 | 2021-07-31 | 03:15:01 |        36.7 |     36.6 |
|   6 | 2021-07-31 | 03:20:01 |        36.8 |     36.3 |
|   7 | 2021-07-31 | 03:25:01 |        36.8 |     36.3 |
|   8 | 2021-07-31 | 03:30:01 |          37 |     36.1 |
|   9 | 2021-07-31 | 03:35:01 |          37 |       36 |

 

5) 측정한 데이터들을 웹페이지를 통해 확인 

DB에 저장된 서버실 온도를 파이썬을 이용하여 그래프로 출력 후, 해당 그래프를 웹페이지에서 볼 수 있도록 한다. 이때, 웹페이지의 하부 구조는 아래와 같다. 

 

Note: 사실 실시간으로 웹페이지에서 확인을 하기 위해선 ganglia 프로그램에서처럼 rrd라는 데이터베이스 형식을 이용하는 것이 좋다고 하지만, 나에게는 너무 어려워 아래와 같이 구성하였다. 아마도 내가 생각했을 때는 굉장히 아래와 같은 방법이 초보스러운 방법 같지만, 다른 사람들에게 도움이 되었으면 좋겠다. 

(1) 파이썬 프로그램 작성
  • PyMySQL이란 패키지를 이용하여 mysql에서부터 쿼리를 보내서 데이터들을 읽어드림 
  • Pandas 패키지를 이용하여 MySQL에서 불러드린 데이터들을 처리하고 그래프를 그림  
    - server_room_temp()라는 함수를 통해서 만들어진 그래프를 지정된 위치에 저장하도록 함. 

- 파일 1: Temp_monitoring.py 

import pymysql
import pandas as pd
import datetime
from matplotlib import pyplot as plt
from matplotlib import dates as md

db = pymysql.connect(user='temp_monitor',   # User 
                     db = 'TEMPERATURE',    # Database that we will use
                     cursorclass=pymysql.cursors.DictCursor)
curs = db.cursor()

########################################################################
# Importing database (MySQL) matched with today's data for server_room
########################################################################
days       = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
now        = datetime.datetime.now()
next_day   = now.date() + datetime.timedelta(days = 1)
today      = days[datetime.datetime.today().weekday()]
dummy_time = datetime.time(0,0,0,0)
now        = now.strftime('%Y-%m-%d')

# make a query to call today's data
sql_server1 = "select * from SERVER_ROOM where date = str_to_date('" + now + "', '%Y-%m-%d')"
curs.execute(sql_server1)
rows = curs.fetchall()          # call all data set
df_server1 = pd.DataFrame(rows)  # df: Dataframe
# transform the data format of df['time'], whose format is datetime.deltatime, to datetime.datetime
df_server1['time'] = df_server1['time'].map(lambda x: datetime.datetime.combine(df_server1['date'][1], dummy_time) + x)

###############################################################################
# Plotting Server room temperature 
###############################################################################

def server1_room_temp(where, day):

     plt.rcParams.update({'font.size': 14})
     # maximum and minimum temperature of our given dateset
     max_temp, min_temp = max(df_server1['temperature']), min(df_server1['temperature'])
     # plotting data set
     df_server1.plot(x = 'time',  y = 'temperature',
             figsize = (15,3),
             xlabel = today,
             ylabel = 'temperature (℃)',
             fontsize = 13,
             legend = False)

     ################ Title
     plt.title("SERVER ROOM's Temperature", fontsize=15)
     ################ plotting options 1) x axis
     ax=plt.gca()
     xfmt = md.DateFormatter('%H:%M')
     ax.xaxis.set_major_formatter(xfmt)
     plt.xlim(pd.Timestamp(now), pd.Timestamp(next_day))
     plt.xticks(rotation=0)
     ################ plotting options 2) y axis
     plt.ylim(min_temp - 2, max_temp + 2)
     ################ plotting option 3)
     plt.grid(True)
     plt.gcf().subplots_adjust(bottom=0.20)

     if day == 'today':
         plt.savefig("/var/www/html/temp_monitor/%s/[%s]server1_room_temp.jpg" %(where, day))
     else:
         plt.savefig("/var/www/html/temp_monitor/%s/[%s]server1_room_temp.jpg" %(where, day))

 

- 파일 2: today_temp.py 

import datetime
from temp_monitoring import *
from matplotlib import pyplot as plt

server1_room_temp('today', 'today')

if datetime.datetime.now().time() > datetime.time(23, 51, 0, 0):
    server1_room_temp('this_week', today)
plt.close('all')

만일 파이썬 프로그램이 정상적으로 작동한다면, 아래와 같은 그래프를 저장한다. 

 

(2) 웹페이지 작성  
간단하게 웹페이지에서 볼 수 있도록 하기 위해, /var/www/html/ 디렉토리 내부에 temp.html이란 파일을 만든 후 아래와 같이 작성하자. 

<!DOCTYPE html>
<html>
    <HEAD>
    <title>CLUSTER MONITOR</title>
    </HEAD>
    <body>
        <h1>server room temperature monitoring webpage</h1>
    </body>
    <body>
        <img src="./temp_monitor/today/[today]server1_room_temp.jpg", width = 48%, height = 48%/>
     </body>
 </html>

 

 

그러면, "<마스터 서버 외부망 ip주소>/temp.html"를 입력하면 웹브라우저에서 아래와 같은 화면을 볼 수 있다. 우리가 매 5분마다 데이터를 얻고 그 데이터로부터 그래프를 생성하도록 설정하였으니, 5분마다 웹페이지에서 새로고침을 하면 온도가 업데이트됨을 확인할 수 있다. 

이와 같은 방법을 이용하면 웹 브라우저에서 온도를 확인할 수 있다.

 

 

728x90

댓글