라즈베리파이 4 #6

jjinny_0609·2023년 3월 8일
0

라즈베리파이

목록 보기
7/8

Flask 웹페이지

Flask, HTML, CSS, Javascript를 이용한 웹페이지 만들기

기본구성

webapps
	- ch066
    	- home
        	- static 
            - templates
  1. 다음과 같이 코드를 작성하고 home 폴더에 저장
from flask import Flask, request
from flask import render_template
import RPi.GPIO as GPIO

app = Flask(__name__)
GPIO.setmode(GPIO.BOARD) #BOARD는 커넥터 pin번호 사용
GPIO.setup(8,GPIO.OUT, initial=GPIO.LOW)

@app.route("/")
def home():
    return render_template("index.html")

@app.route("/led/on")
def led_on():
    try:
        GPIO.output(8, GPIO.HIGH)
        return "ok"
    except expression as identifer:
        return "fail"
    
@app.route("/led/off")
def led_off():
    try:
        GPIO.output(8, GPIO.LOW)
        return "ok"
    except expression as identifier:
        return "fail"
if __name__ == "__main__":
    app.run(host="0.0.0.0")    
       
    
  1. 다음과 같이 코드를 작성하고 home 폴더 아래 templates 폴더에 저장
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>HOME NETWORK</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <div class="header">
            <h2>HOME IoT</h2>
        </div>
        <div class="main">
            <div>
                <button onclick="led_on()">LED ON</button>
            </div>
            <div>
                <button onclick="led_off()">LED OFF</button>
            </div>
        </div>
        <div id="result">

        </div>
    </div>
    <script>
        function led_on(){
            fetch("/led/on")
            .then(Response=> Response.text())
            .then(data=>{
                let result = document.querySelector("#result");
                if(data=="ok"){
                    result.innerHTML = "<h1>LED is running</h1>";
                }else{
                    result.innerHTML = "<h1>error</h1>";
                }
            });
        }
        function led_off(){
            fetch("/led/off")
            .then(Response=> Response.text())
            .then(data=>{
                let result = document.querySelector("#result");
                if(data=="ok"){
                    result.innerHTML = "<h1>LED is stopping</h1>";
                }else{
                    result.innerHTML = "<h1>error</h1>";
                }
            });
        }
    </script>
</body>    
</html>
  1. 다음과 같이 코드를 작성하고 home 폴더 아래 static 폴더에 저장
body{
    background-color:antiquewhite;
}

.container{
    width: 700px;
    margin: 0 auto;
    text-align: center;
}

.main{
    display: flex;
}

.main div{
    flex:1;
}

.main div button{
    background-color: rgb(192, 144, 144);
    width: 150px;
    height:80px;
    border-radius:10px;
}
  1. 실행방법은 다음과 같으며 터미널을 열고 해당폴더로 이동하여 다음과 같이 입력
python home.py
  • 라즈베리 파이에서 브라우저를 열어서 확인할 경우
http://localhost:5000/
  • 다른 pc에서 브라우저를 열어서 확인할 경우
~~http://192.168.0.0 ~~(본인의 ip주소)

05. 결과화면

  1. [LED ON] 버튼을 클릭

  1. [LED OFF] 버튼을 클릭

  1. 오류를 발생시켜 보자. index.py 파일을 다음과 같이 수정한다.


output GPIO핀 번호가 바뀌게 되면서 LED를 찾지 못하기 때문에 try 부분에서 오류가 발생하고 exception 부분으로 넘어가게 됩니다. 예외처리를 사용하게 되면 예상하지 못한 서버 오류로 서버가 멈추는 일이 발생하지 않습니다.

  1. 다시 실행해보면 error를 return 하게 된다.

fetch() 함수 이해하기

index.html 코드에서 fetch라는 문법이 나오게 됩니다. 자바스크립트의 문법.
ajax를 이용한 비동기 통신을 할 때 사용하는 라이브러리입니다. 예전에는 ajax 요청 시에 jQuery를 많이 사용하였는데 최근에는 자바스크립트가 제공해주는 fetch를 많이 사용합니다.
fetch를 통해서 index.py의 led_on() 메서드를 호출하게 되고 그 결과를 response를 통해서 받습니다. led_on 메서드 호출시에 실제 led가 on이 되게 됩니다. 그리고 정상적으로 on이 되면 ok를 return 하게 됩니다. return 된 값을 fetch().then(response) 이 부분에서 then()이 받게 됩니다. then()은 fetch가 완료 된 뒤에 호출이 됩니다.

fetch는 요청 시에는 pending(대기)되고 있다가 요청이 완료되면 then(response)로 요청에 대한 결과를 return 해주게 됩니다. 이를 통해 콜백 지옥을 벗어날 수 있습니다.
promise기술이 들어가 있기 때문입니다. return된 결과는 "ok"메시지뿐만 아니라 수많은 정보를 가지고 있습니다. 이런 정보를 자바스크립트 오브젝트로 만들어서 요청한 쪽으로 return 해주게 되는 것입니다. 이 수많은 정보 중에서 우리에게 필요한 데이터는 "ok" 메시지입니다.

  • fetch 요청의 response 객체

"ok" 메시지를 받으려면 then()이 한번 더 필요합니다.
첫 번째 then()에서는 위 그림과 같이 전체 응답 프로젝트를 받습니다. 두 번째 then()은 그 많은 데이터 중 "ok"라는 메시지를 필터링 해줍니다. 서버 쪽에서 return되는 결과가 String(문자열)이면 text() 함수를 이용하고, JSON이면 json() 함수를 이용하여 받으면 됩니다.


IP, Port, Process 개념 잡기

IP

IP는 internet protocol의 약자로, 송신 호스트와수신 호스트가 데이터를 서로 주고 받는데 필요한 프로토콜(규약)을 의미한다. 여기서 데이터는 패킷으로 분할되어 전송되고 받은 쪽에서는 분할된 패킷을 조립하게 된다.

Port

Process

  1. 다음과 같이 코드를 작성
from flask import Flask, request
import RPi.GPIO as GPIO

app = Flask(__name__)

LED = 8
GPIO.setmode(GPIO.BOARD) #BOARD는 커넥터 pin번호 사용
GPIO.setup(LED, GPIO.OUT, initial=GPIO.LOW)

@app.route("/led/<state>")
def led(state):
    if(state == "on"):
        GPIO.output(LED, GPIO.HIGH)
        return "LED ON"
    elif(state == "off"):
        GPIO.output(LED, GPIO.LOW)
        return "LED OFF"
    else:
        return "error"
    

if __name__ == "__main__":
    app.run(host="0.0.0.0")
  1. 웹브라우저를 열고 다양한 방식으로 실행

  2. 새로운 터미널을 열고 포그라운드 프로세스를 확인 ( ps -f )

  3. 백그라운드 프로세스를 확인 ( ps -e )

  4. | grep을 이용하여 process.py 프로세스만 확인

  5. 2941 pip 값을 가진 프로세스를 죽임 (sudo kill 2941)

  6. 사용중인 Port를 찾아서 프로세스를 종료

    process.py를 실행하게 되면 5000번 포트가 개방됨 (지금은 개방하지 않은 상태)
    sudo kill을 이용해서 프로세스를 종료시키면 포트가 충돌하는 상황에서 해결할 수 있음

OSError : [Errno 98] Address already in use

위의 메시지가 출력되면 위의 방법을 이용해서 프로세스를 종료


cron과 daemon 개념잡기

크론(cron)

주기적인 실행이 필요할때 사용
예를 들어 매일 자정에 데이터를 백업하고 싶을때나, 매일 아침 7시가 되면 led를 작동시키고 싶을때 사용한다.

  1. 다음과 같이 코드를 작성하고 저장
# -*- encoding: utf-8 -*-

import RPi.GPIO as GPIO
import time

GPIO.cleanup() #한글

LED = 8
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED, GPIO.OUT, initial=GPIO.LOW)

try:
    num = 0
    while(True):
        time.sleep(1)
        GPIO.output(LED, GPIO.HIGH)
        time.sleep(1)
        GPIO.output(LED, GPIO.LOW)
        num = num + 1
        if(num == 5):
            GPIO.cleanup()
            break
except KeyboardInterrupt:
    GPIO.cleanup()
  1. led.py 프로그램을 실행
$ python led.py
  1. led.py 파일 cron에 등록
crontab -e

crontab을 열고 가장 아래줄에 다음과 같이 적어줍니다.

* * * * * sudo python /home/pi/webapps/ch06/cron/led.py

위 코드는 1분마다 해당 파일을 실행해라는 뜻이다. 등록해두고 저장하고 빠져나오면 1분마다 5초씩 깜빡거리는 LED가 작동하는 것을 확인할 수 있습니다.
crontab을 더 이상 사용하고 싶지 않다면 어떻게 해야하나요?

$ crontab -e


daemon(데몬) 개념잡기

크론이 주기를 가지고 실행되는 것이라면 데몬은 계속 실행되는 것입니다.

  1. 다음과 같이 코드를 작성하고 저장
#! /usr/bin/env python3.9.2
#해당 파일을 다른곳에서 실행할 때 pyton실행파일을 사용하여 실행해라

import RPi.GPIO as GPIO
import time

GPIO.cleanup()

LED = 8
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED, GPIO.OUT, initial=GPIO.LOW)

try:
    num = 0
    while(True):
        time.sleep(1)
        GPIO.output(LED, GPIO.HIGH)
        time.sleep(1)
        GPIO.output(LED, GPIO.LOW)
        num = num + 1
        if(num == 5):
            GPIO.cleanup()
            break
except KeyboardInterrupt:
    GPIO.cleanup()
  1. rc.local 파일을 수정합니다.
$ sudo nano /etc/rc.local

&을 마지막에 붙이면 백그라운드로 실행한다는 의미

  1. led2.py 파일에 실행권한을 줍니다. 소유자, 소유그룹, 모든 유저에게 모든 권한을 줍니다.

  2. 재부팅해보면 LED가 5초동안 깜빡이고 있는 것을 확인할 수 있다.
    부팅 도중에 led가 켜지는 경우는 부팅 시에 GPIO 포트가 정상 작동하고 있는지 테스트하는 것이기 때문에 신경쓰지 않아도 된다. 부팅이 거의 완료될 시점부터 led가 5초 동안 깜빡이고 있는 것을 확인할 수 있다.


공공데이터 활용하기

공공데이터 포털

공공기관이 생성 또는 취득하여 관리하고 있는 공공테이터를 한 곳에서 제공하는 통합 창구입니다.
포털에서는 국민이 쉽고 편리하게 공공데이터를 이용할 수 잇도록 파일데이터, 오픈API, 시각화 등 다양한 방식으로 제공하고 있으며 누구라도 쉽고 편리한 검새을 통해 원라는 공공데이터를 빠르고 정확하게 찾을 수 있습니다.
https://www.data.go.kr/index.do

공공데이터 포털을 활용하여 온습도 센서없이 날씨를 확인할 수 있는 방법
4가지 단계를 거쳐야함.

첫째, 회원가입진행

둘째, 공공 데이터를 신청하고 승인을 받기
자동승인 되는 데이터도 있고, 직접승인을 받아야 하는 데이터도 있으므로 확인하고 신청하기

셋째, JSON 데이터 타입에 대한 이해가 필요합니다. JSON은 Int, String, Object, Array 4가지 데이터 타입으로 이루어져 있습니다.

넷째, python을 이용하여 Json 데이터를 공공데이터로부터 받아올수 있을지에 대한 코드에 대한 이해가 필요하다. 공공데이터 포털에서 샘플코드를 제공해주기 때문에 바로 사용하면 되지만 pyhton 버전에 따라 수정해서 사용해야 할 수도 있다.


공공데이터 신청하기

  1. https://www.data.go.kr/index.do 회원가입 진행

  2. 신청 및 승인을 받기위해 데이터 선정

  3. 검색창에 '동네예보정보조회서비스'를 입력하고 검색을 누릅니다.

  4. 오픈 API 메뉴를 선택

  5. 아래 이미지와 일치하는 것을 선택

  6. [활용신청] 버튼을 클릭


    상세기능정보는 모두 저장

활용신청 누르니 승인완료된 모습

  1. 샘플테스트를 위해 일반 인증키를 복사

    인증키와 base_data를 오늘날짜로 수정

  2. 미리보기를 누르면 다음과 같은 XML 데이터를 볼 수 있음.


공공데이터 분석하기

api에 대한 자세한 설명이 필요하면 기술문서를 참고하면 활용하는데 큰 도움이됨.

XML에 모르는 항목명은 기술문서에 자세히 기재 되어 있으므로 참고하면됨.

기술문서에서 코드값에 대한 정보와 단위를 볼 수 있다.

  • dataType을 XML에서 JSON으로 변경해서 볼 수도 있음.


파이썬을 활용하여 온습도 확인하기

  1. 마이페이지

  2. 기상청단기예보 ((구)동네예보) 조회서비스

  3. 상세설명

  4. 초단기 실황조회

  5. 아래로 내리면 샘플코드를 볼 수 있다.

  6. VNC를 이용하여 라즈베리 파이로 돌아갑니다. 다음과 같은 폴더 구조를 생성합니다.

webapps
	- ch06
    		- weather
            		-weather_test.py
  1. 서비스키 값은 다음과 같이 복사하여 붙여주시면 됩니다.

  2. 샘플코드 예제

# Python3 샘플 코드 #

import requests
from urllib.parse import unquote

url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst'
params ={
    'serviceKey' : unquote('MhbDPOYDZtlZbBdADrT1Rk0b2P4tAbBxySM6fWkMfJvQSM7r6c1SS9MSpYNJtpbsuCdpMdDfK7cwIyOGiNegGQ'),
    'pageNo' : '1',
    'numOfRows' : '1000',
    'dataType' : 'JSON',
    'base_date' : '20230308',
    'base_time' : '0600',
    'nx' : '55',
    'ny' : '127'}
# '서비스키'에 : unquote 앞에 붙이고 본인 해당키 값'

response = requests.get(url, params=params)
print(response.content)
profile
뉴비 개발자 입니다. velog 주소 : https://velog.io/@jjinny_0609 Github 주소 :

0개의 댓글