코딩 이야기

Flask를 활용하여 센서 제어하기 본문

라즈베리파이

Flask를 활용하여 센서 제어하기

별메아리 2023. 3. 7. 14:51
728x90

파이썬은 자체적으로 내장 웹서버 모듈을 가지고 있습니다. 웹프로그램을 만드는 방법으로는 여러가지가 있지만 우리는 경량 웹 프레임워크인 Flask를 사용해 보겠습니다.

 

__Flask 웹서버 구축하기

폴더 구성과 파일을 구성을 다음과 같이 합니다.

webapps/ch06/helloworld/app_start.py

다음과 같이 코드를 작성하고 저장합니다.

from flask import Flask
app = Flask(__name__)
@app.route("/")
def helloworld():
    return "Hello World"

if __name__ == "__main__":
    app.run(host="0.0.0.0")

실행방법은 터미널을 열고 다음과 같이 입력합니다.

$cd /home/piwebapps/ch06/helloworld
$ python app_start.py
f5@raspberrypi:~/webapps/ch06/helloworld $ python app_start.py
 * Serving Flask app "app_start" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [07/Mar/2023 12:41:12] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [07/Mar/2023 12:41:12] "GET /favicon.ico HTTP/1.1" 404 -

웹 브라우저를 열고 다음과 같이 주소를 입력하면 완성입니다.

http://localhost:5000

코드 리뷰

from flask import Flask

from flask에서 flask는 폴더를 의미합니다.

import Flask에서 Flask는 클래스명을 의미합니다.

 

위 문장은 라이브러리 path가 적용된 기본 폴더에서 flask라는 폴더를 찾고 그 폴더 안에 있는 Flask클래스를 import 하라는 뜻입니다. import를 통해서 함수만 호출할 수도 있습니다.

form 모듈명 import 함수명

라이브러리 path가 적용된 기본 폴더에서 모듈명을 찾고 그 모듈에 있는 특정함수를 import 하는 것 입니다.

app = Flask(__name__)

app은 Flask 객체를 가지게 됩니다. 

__name__은 내 파일명,모듈(함수의 모움)명을 의미합니다. Flask 객체가 생성될 때 app_start.py 파일명을 이용하여 객체를 생성하게 됩니다. (__name__은 내장변수이면서 전역변수)

@app.route("/")

app.route("/")는 라우팅을 위한 뷰 함수를 등록하는 코드입니다.

클라이언트가 URI로 ("/") 요청을 하게 되면 해당 route 데코레이터 아래에 있는 뷰 함수가 자동호출 됩니다.

예를 들어 ("/") 이렇게 되어 있으니 http://localhost:5000/으로 요청하게 되면 해당 route가 호출됩니다.

@app.route("/helloworld")

위와 같다면 호출방법은 http://localhost:5000/helloworld가 됩니다.

 

"Hello World"는 함수가 종료될 때 요청한쪽으로 응답되는 String값입니다.

def Helloworld():
	return "Hello World"

route 데코레이터를 통해서 뷰 함수가 호출될 때 함수명 helloworld는 마음대로 정해도 됩니다.. 단 클라이언트가 주소요청을 하게 되면 뷰 함수가 호출되게 되는데 이때 뷰 함수에는 필수적으로 return문이 있어야 합니다..

 여기서 json을 리턴 할 수도 있고ㅗ dict 자료형을 리턴할 수도  있고 필요에 따라 html 페이지로 렌더링을 하는 것도 가능합니다.

 

app.run()이 호출되면 웹서버가 동작합니다.

if__name__=="__main__":
	app.run(host="0.0.0.0")

__name__은 두 가지 이름을 가집니다. 첫 번째는 내 모듈명 app_start.py이고 두 번째 이름은  app_start.py파일을 직접 터미널에서 실행하게 되면 __main__ 이라는 이름을 가지게 됩니다.

 만약에 다른 파일에서 app_start.py파일을 import해서 사용하게 되면 __name__이 __main__이라는 이름이 될 수 없습니다.  해당 파일을 직접 실행 시킬 때만 가능합니다. 위 문장은 app_start.py 파일을 직접 실행시켰을때만 "서버를 작동시켜" 라는 뜻입니다. 

app.run()은 서버를 시작하라는 명령어이고 여기에 들어가는 인자 0.0.0.0 은 어떤 ip에서 요청이 들어와도 응답해준다는 뜻입니다.

 

_Flask 라우팅

Flask에서 URL을 처리하는 방법을 다른 말로 URI 디스패치라고 합니다. 디스패치는 아주 단순한 일을 합니다. 사용자가 입력한 URI를 지켜보고 있습니다. 그리고 URI를 분석하여 올바른 길로 인도해주는 역할을 합니다.

 

Flask LED 제어 정적 라우팅

from flask import Flask
import RPi.GPIO as GPIO

app = Flask(__name__)

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

@app.route("/")
def helloworld():
    return "Hello World"

@app.route("/led/on")
def led_on():
    return "LED ON"

@app.route("/led/off")
def led_off():
    return "LED OFF"

@app.route("/gpio/cleanup")
def gpio_cleanup():
    GPIO.cleanup()
    return "GPIO CLEANUP"

if __name__ == "__main__":
    app.run(host="0.0.0.0")

Flask LED 제어 동적 라우팅 <산형괄호>

동적으로  변경되는 URL의 뷰 함수를 사용하기 위해서는 산형괄호<>을 이용해서 변수를 전달해야 합니다. 주의할 점은 해당 변수가 클라이언트로 부터 URL로 전달되면 함수의 매개변수로 받아줘야 사용이 가능하다는 점입니다.

from flask import Flask
import RPi.GPIO as GPIO

app = Flask(__name__)

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

@app.route("/")
def helloworld():
    return "Hello World"

'''
@app.route("/led/on")
def led_on():
    GPIO.output(LED, GPIO.HIGH)
    return "LED ON"
    
@app.route("/led/off")
def led_off():
    GPIO.output(LED, GPIO.LOW)
    return "LED OFF"    
'''

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

@app.route("/gpio/cleanup")
def gpio_cleanup():
    GPIO.cleanup()
    return "GPIO CLEANUP"

if __name__ == "__main__":
    app.run(host="0.0.0.0")

Flask LED 제어 동적 라우팅 <쿼리 스트링>

동적으로 변경되는 URL함수는 다음과 같이 쿼리 스트링 방식으로도 호출 가능합니다. 쿼리 스트링이란http://localhost:5000/led?state=on 이런식으로 주소 호출이 올 떄 ?뒤에 오는 것을 말합니다. ?뒤에 오는 것들은 HTTP요청에서 GET방식으로 요청이 가능합니다. 전달되는 데이터를 request 클래스의 args 객체를 사용하여 받을 수 있습니다. 다음과 같이 flask 모듈에서 request를 import해야 request를 사용할수 있습니다.

from flask import Flask
import RPi.GPIO as GPIO

app = Flask(__name__)

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

@app.route("/")
def helloworld():
    return "Hello World"

'''
@app.route("/led/on")
def led_on():
    GPIO.output(LED, GPIO.HIGH)
    return "LED ON"
    
@app.route("/led/off")
def led_off():
    GPIO.output(LED, GPIO.LOW)
    return "LED OFF"    
'''

@app.route("/led")
def led():
    state = request.args.get("state")
    if state == "on":
        GPIO.output(LED, GPIO.HIGH)
    else:
        GPIO.output(LED, GPIO.LOW)
    return "LED "+state

@app.route("/gpio/cleanup")
def gpio_cleanup():
    GPIO.cleanup()
    return "GPIO CLEANUP"

if __name__ == "__main__":
    app.run(host="0.0.0.0")

뷰 함수에 쿼리스트링을 받기 위한 코드가 준비되어 있지만 주소 요청시 쿼리스트링을 전달하지 않았기 때문입니다 이럴 경우에는 어떻게 해야 할까요? 물론 쿼리스트링을 정상적으로 보내게 되면 오류가 나지 않겠지만 무엇이든 미리 대비하면 좋습니다.

 

파일을 수정해 봅시다

@app.route("/led")
def led():
    state = request.args.get("state", "error")
    if state == "on":
        GPIO.output(LED, GPIO.HIGH)
    else state == "off":
        GPIO.output(LED, GPIO.LOW)
    elif state == "error":
    	return "쿼리스트링 state가 전달되지 않았습니다."
    else:
    	return "잘못된 쿼리스트링이 전달되었습니다."
    return "LED "+state

 

728x90
Comments