이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Raspberry Pi와 Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560), WiFi 모듈을 사용 합니다.

python-web-server

Raspberry Pi - Webserver(Python)
Python(Flask)를 이용한 Raspberry Pi Webserver

이 페이지는 간단한 HTTP server(Flask를 이용)와 Web 상에서 실시간으로 양 방향 통신을 가능하게 하는 WebSocket을 이용한 원격제어에 대한 이해를 위한 페이지 이다.




  • Python를 이용한 Webserver 환경 만들기
    • Flask 설치 하기
    • Flask는 Python으로 작성된 웹 응용 프로그램 프레임 워크이다.

        Raspberry Pi에는 Python과 Python을 위한 Flask Library가 이미 설치되어 있기 때문에 별도로 설치 할 필요가 없다.

      • 다음 명령으로 Python3에 설치된 Python package를 확인 할 수 있다.
      • pip3 list

    • web file(Python file, html file, css file)을 저장하기 위한 폴더 만들기
      • Python web file(html)를 저장할 Directory(webapp)를 만든다.
      • mkdir webapp

      • webapp 폴더에 web file(html)를 저장할 Directory(templates)를 만든다.
      • mkdir templates

      • webapp 폴더에 css file 등를 저장할 Directory(static)를 만든다.
      • mkdir static


  • Python를 이용한 Raspberry Pi Webserver
    • 첫번째 Web server 만들기
      • Windows PC에서 Notepad++ 편집기를 사용하여 web server(first.py) File을 아래와 같이 작성 한다.
      • first.py

        
        #!/user/bin/env python
        # coding=utf8
        
        # Importing flask module
        from flask import Flask
        
        # Flask 생성자는 현재 모듈 이름 (__name__)을 인수로 사용한다.
        app = Flask(__name__)
        
        # Flask 클래스의 route() 함수는 Decorator(데코레이터)로,
        #  연결된 함수를 호출하는 URL(이 예에서는 '/')을 알려준다.
        # 이 예에서 '/' URL은 first_web() 함수와 바인딩 된다.
        @app.route('/')
        def fist_web():
            return 'First web server'
        
        # Flask 클래스의 run() 메소드는 애플리케이션을 실행한다.
        # run() method의 모든 parameter는 모두 Optional 이기 때문에 생략 할 수 있다.
        # host parameter는 Defaults 값이 127.0.0.1
        #  (이 경우 localhost 에서 만 접속 할 수 있음) 이다.
        #  host='0.0.0.0' 인 경우 Web server를 외부에서 접속 할 수 있도록 한다.
        # port  parameter는 Defaults 값이 5000 이다.
        #  이 예에서는 2880 번을 사용하였다. 포트 번호는 각자 적당한 값으로 별경 할 수 있다.
        # 외부에서 Web server에 접속하기 위하여는 공유기에서 포트포워드 설정을 하여야 한다.
        # debug parameter는 Defaults 값이 False 이다.
        #  개발 단계에서 Debug information 이 필요한 경우 True로 설정 한다.
        if __name__ == '__main__':
            app.run(host='0.0.0.0', port=2880, debug=True)
            

      • WinSCP를 이용하여 Raspberry Pi의 webapp 폴더로 프로그램을 전송한다.
      • 다음 명령으로 first.py를 실행 한다.
      • python3 first.py

      • web browser를 이용 하여 다음과 같이 Web server에 연결하고 실행 결과을 확인 한다.
      • http://[RaspberryPi_IP]:2880/

        위에서 [RaspberryPi_IP]는 Raspberry Pi의 IP Adress


    • Routing 예
      • 원하는 Web page를 직접 Acces 하기 위하여 Routing 기술을 사용 한다.

      • Windows PC에서 Notepad++ 편집기를 사용하여 web server(hello.py) File을 아래와 같이 작성 한다.
      • hello.py

        
        #!/user/bin/env python
        # coding=utf8
        
        # Importing flask module
        from flask import Flask
        
        # Flask 생성자는 현재 모듈 이름 (__name__)을 인수로 사용한다.
        app = Flask(__name__)
        
        # Flask 클래스의 route() 함수는 Decorator(데코레이터)로,
        #  연결된 함수를 호출하는 URL(이 예에서는 '/'hello)을 알려준다.
        # 이 예에서 '/hello' URL은 hello_world() 함수와 바인딩 된다.
        @app.route('/hello')
        def hello_world():
            return 'Hello world'
        
        if __name__ == '__main__':
            app.run(host='0.0.0.0', port=2880, debug=True)
            

      • WinSCP를 이용하여 Raspberry Pi의 webapp 폴더로 프로그램을 전송한다.
      • 다음 명령으로 hello.py를 실행 한다.
      • python3 hello.py

      • web browser를 이용 하여 다음과 같이 Web server에 연결하고 실행 결과을 확인 한다.
      • http://[RaspberryPi_IP]:2880/hello

        위에서 [RaspberryPi_IP]는 Raspberry Pi의 IP Adress


    • HTML 파일(Web page)을 전송 받기
      • render_template() 함수를 사용하여 Web browser에서 HTML 파일(Web page)을 전송 받는다.

      • Windows PC에서 Notepad++ 편집기를 사용하여 web server(first-html.py) File을 아래와 같이 작성 한다.
      • first-html.py

        
        #!/user/bin/env python
        # coding=utf8
        
        from flask import Flask, render_template
        
        app = Flask(__name__)
        
        @app.route('/')
        def index():
            return render_template('first-html.htm')
        
        if __name__ == '__main__':
            app.run(host='0.0.0.0', port=2880, debug=True)
            

        Flask는 HTML file을 templates folder에 있는 것으로 간주하기 때문에 이 예를 위한 폴더 구성과 파일 위치는 아래와 같이 구성 하여야 한다.

        • wepapp   <- Folder: 이 예에서 Application 폴더 이름을 wepapp로 하였다.
          • first-html.py   <- Python file
          • templates   <- Folder
            • first-html.htm   <- html file
      • Windows PC에서 Notepad++ 편집기를 사용하여 first-html.htm File을 아래와 같이 작성 한다.
      • first-html.htm 보기

      • WinSCP를 이용하여 first-html.py 파일(webapp/ 폴더)과 first-html.htm 파일(webapp/templates/ 폴더)을 Raspberry Pi의 해당 폴더로 전송한다.
      • 다음 명령으로 first-html.py를 실행 한다.
      • python3 first-html.py

      • web browser를 이용 하여 다음과 같이 Web server에 연결하고 실행 결과을 확인 한다.
      • http://[RaspberryPi_IP]:2880/

        위에서 [RaspberryPi_IP]는 Raspberry Pi의 IP Adress



  • Web checkbox을 이용한 LED 제어
    • 실험을 위한 준비
      • Raspberry Pi Pin11(GPIO 17)에 1번 LED를 연결 한다.
      • Raspberry Pi Pin13(GPIO 27)에 2번 LED를 연결 한다.
      • GPIO Pin과 LED 연결하기
        • Raspberry Pi의 GPIO Pin과 330옴 저항의 한 단자를 연결 한다.
        • LED의 + 단자와 330옴 저항의 다른 단자를 연결 한다.
        • LED의 - 단자을 Breadboard의 GND 에 연결 한다.
        • Raspberry Pi의 GND(Pin9)과 Breadboard GND를 연결 한다.

        Raspberry Pi LED 제어하기를 참고하기 바람.

    • Editor를 사용하여 webapp Directory에 py-checkbox-led.py File을 만들고 아래와 같이 편집 한다.
    • py-checkbox-led.py

      
      #!/user/bin/env python
      # coding=utf8
      from flask import Flask, render_template, request
      from gpiozero import LED
      
      app = Flask(__name__)
      import json
      
      led = [LED(17),LED(27)]
       
      @app.route('/')
      def checkBoxLED():
          return render_template('py-checkbox-led.htm')
      
      @app.route('/checkBoxLEDControl', methods=['POST'])
      def LEDControl():
          # Checkbox의 Check list(Check 상태로 HTML File에서 Value로 정의 됨)를 갖어 온다.
          checkbox = request.form.getlist('check')
          #print('checkbox: ',checkbox)
          # checkbox에는 Check된 Checkbox의 상태만 포함되어 있기 때문에
          # Check 되지 않은 Checkbox의 상태도 포함하기 위하여 checkList[ ]를 정의한다.
          checkList = [0, 0]
          checkListLen = len(checkList)
          # 모든 LED를 Turn off 한다.
          for i in range(0, checkListLen):
              led[i].off()
          # Checkbox가 Check된 LED를 Turn on 한다. 	
          for checkboxNo in checkbox:
              i = int(checkboxNo)
              led[i].on()
      		
          # 현재 모든 LED의 상태(On, Off)를 checkList에 저장한다.
          for i in range(0, checkListLen):
              if led[i].is_active == True:
                  checkList[i] = 1
              else:
                  checkList[i] = 0
          #print('checkList: ',checkList)
      
      	# 현재 LED의 상태(On, Off)를 표시하는 checkList를 Web page에 Return 한다.
          return json.dumps({'status':'OK','checkbox':checkList});
      
      @app.route('/checkBoxLEDGet', methods=['GET'])
      def LEDGet():
          # Checkbox의 Check list(Check 상태로 HTML File에서 Value로 정의 됨)를 갖어 온다.
          getMsg = request.args.get('getLED')
          #print('getMsg: ',getMsg)
          # checkbox에는 Check된 Checkbox의 상태만 포함되어 있기 때문에
          # Check 되지 않은 Checkbox의 상태도 포함하기 위하여 checkList[ ]를 정의한다.
          checkList = [0, 0]
          checkListLen = len(checkList)
      	
          # 현재 모든 LED의 상태(On, Off)를 checkList에 저장한다.
          for i in range(0, checkListLen):
              if led[i].is_active == True:
                  checkList[i] = 1
              else:
                  checkList[i] = 0
          #print('checkList: ',checkList)
      
      	# 현재 LED의 상태(On, Off)를 표시하는 checkList를 Web page에 Return 한다.
          return json.dumps({'status':'OK','checkbox':checkList});
       
      if __name__ == '__main__':
         app.run(host='0.0.0.0', port=2880, debug=True)
          

    • Windows PC에서 Notepad++ 편집기를 사용하여 py-checkbox-led.htm File을 아래와 같이 작성 한다.
    • py-checkbox-led.htm

      py-checkbox-led.htm을 실행한 Web page 예

    • WinSCP를 이용하여 py-checkbox-led.py 파일(webapp/ 폴더)과 py-checkbox-led.htm 파일(webapp/templates/ 폴더)을 Raspberry Pi의 해당 폴더로 전송한다.
    • 다음 명령으로 py-checkbox-led.py를 실행 한다.
    • python3 py-checkbox-led.py

    • web browser를 이용 하여 다음과 같이 Web server에 연결하고 실행 한다.
    • http://[RaspberryPi_IP]:2880/

      위에서 [RaspberryPi_IP]는 Raspberry Pi의 IP Adress

    • LED 제어 실험하기
      • Turn on 하려고 하는 LED 번호에 해당되는 Chekbox를 Check 하고 "LED Control" 버튼을 누르면 Check 된 번호의 LED가 Turn on 된다.
      • "Get LED Status" 버튼을 누르면 현재 Turn on 된 LED에 대응하는 Checkbox 가 Check 된다. 동작 확인을 위하여 Checkbox를 Clear 한 다음 이 명령을 실행 한다.

  • Raspberry Pi 시작 시 자동으로 프로그램 시작 하도록 하기
    • Python Script를 Background에서 실행 하기
      • Python Script의 윗 부분에 아래 Code를 삽입 한다.
      • #!/usr/bin/env python3

      • 아래 명령으로 Python Script File의 Permissions을 실행 가능한 속성으로 변경 한다.
      • chmod +x file-name.py

      • 아래 명령으로 Python Script File을 실행 한다.
      • nohup python3 file-name.py &

      • Python Script File의 실행중 발생하는 Output(log)는 nohup.out에 저장 된다.
    • Raspberry Pi 시작 시 자동으로 프로그램이 시작 하도록 하기 위한 설정
      • /etc/rc.local File에 Editor를 사용하여 다음 명령을 삽입 한다.
        • sudo nohup python3 (path)/(run flie name) &
        • 예: sudo nohup python3 /home/pi/python/webapp/py-checkbox-led.py &
        • & 문자는 프로그램이 Background에서 실행 되도록 함. 소유자: root
    • Background에서 실행 중인 Process를 확인 하고 정지 하기
      • 다음 명령으로 Background 에서 실행 중인 python3 Process PID를 확인 한다. 윗 예에서 실행 프로그램 이름은 py-checkbox-led.py 이지만 실행 Process 이름은 python3 임.
      • ps -A | grep (Process name)

        예: ps -A | grep python3

      • 다음 명령으로 실행 중인 python3 Process를 정지 한다.
      • sudo kill pid (pid는 ps 명령으로 확인한 python3 process의 pid 번호 임.)