라즈베리파이3에 API 서버를 올리는 작업은 흔히 하는 대로 Flask를 사용하기로 하였다.
virtualenv를 쓰는 경우가 많으나, 라즈베리파이는 이 용도 전용으로 쓸 것이므로 굳이 가상환경을 설정할 필요가 없을 것 같아 이를 이용하지 않고 그냥 설치하였다.
웹 상에 있는 간단한 테스트 프로그램을 만들어 웹서버를 올려 보았다.
python3 app.py
그런데 라즈베리파이3가 너무 느려서, 로컬 호스트로 테스트하는 것은 역시 무리였다. 라즈베리파이에서 브라우저를 실행시키는 것 자체가 많은 인내를 요구했다.
차라리 같은 네트워크의 다른 컴퓨터에서 액세스하는 편이 낫다고 보고 방법을 찾아보니 다음과 같이 하라고 한다.
flask run -h 0.0.0.0
라즈베리파이에서 이를 실행하면 터미널 상에서 현재 폴더에 있는 app.py를 찾아서 실행한다.
정상적으로 실행이 되면 이제 다른 PC의 브라우저에서 라즈베리파이의 IP로 http 접속을 하고, html의 내용을 볼 수 있다.
여기까지는 웹에서 흔하게 찾을 수 있는 내용이다.
그런데...
나에게 필요한 것은 6바이트의 명령 데이터와 각 명령에 따라 그 길이가 서로 다른 특정 데이터를 함께 보낼 수 있는 방법이었다. 그것도 바이너리 데이터로 보내야 한다.
전송시에 보통 사용하는 JSON의 예제를 보면 텍스트 데이터를 기반으로 하고 있고, 그 길이도 고정된 것이 대부분이라 별로 도움이 되지 않았다.
네트워크, 웹 프로그래밍 부분은 내가 하던 분야가 아니라 잘 알지 못한다.
결국 한참 여기저기 뒤적거렸지만 뾰족한 방법을 찾지 못하고 머리만 싸매고 있을 수 밖에 없었다.
그런데 그때 최근에 내가 직접 고용한 한 신입의 존재가 떠올랐다.
이름이 좀 색다른데, 성은 쳇씨고 이름은 GPT라고 한다.
질문을 던지자 쳇GPT는 바로 JSON대신 binary protocol을 사용하라고 조언을 해주었다.
If you want to use a binary protocol to send commands and data over the internet,
you can still use HTTP as the underlying protocol.
However, instead of sending JSON-encoded data in the request body,
you would send binary data.
One way to achieve this is by using the Content-Type header to indicate
that the request body contains binary data.
The Content-Type header specifies the type of data being sent in the request
and can include parameters that further define the format of the data.
For example, you could use a Content-Type header with the value application/octet-stream
to indicate that the request body contains binary data with no specific format.
Here's an example of how you could make a request using binary data:
python
Copy code
from flask import Flask, request
import struct
app = Flask(__name__)
@app.route('/api', methods=['POST'])
def handle_api():
# Read the binary data from the request body
data = request.data
# Parse the binary data according to the protocol
command = struct.unpack('6B', data[:6])
payload = data[6:]
# Handle the command and payload
# ...
# Return a response
return 'OK'
In this example, we're sending a 6-byte command followed by a 9-byte payload
using the requests library in Python. The Content-Type header is set to
application/octet-stream to indicate that the request body contains binary data.
On the server side,
you would need to read the binary data from the request body and parse it
according to your binary protocol. You could use a library like struct in
Python to help with parsing the binary data.
Keep in mind that using a binary protocol can make debugging and testing more
difficult since the data is not human-readable. You may also need to consider
security measures, such as encryption, to protect the data being sent over the internet.
chatGPT는 테스트 코드도 만들어 주었는데, Content-Type을 application/octet-stream으로 해서 보내는 방법이라고 한다.
몇가지 추가적인 질문을 통해 다음과 같은 테스트 코드를 만들 수 있었다.
from flask import Flask, request, make_response
import struct
app = Flask(__name__)
@app.route('/api', methods=['POST'])
def handle_api():
# Read the binary data from the request body
data = request.data
# Parse the binary data according to the protocol
command = struct.unpack('6B', data[:6])
payload = data[6:]
print(command, file=sys.stderr)
print(payload, file=sys.stderr)
# Handle the command and payload
# ...
# Create a 6-byte response
response_data = b'\x01\x02\x03\x04\x05\x06'
# Create a response with the 6-byte data
response = make_response(response_data)
# Set the Content-Type header to indicate binary data
response.headers['Content-Type'] = 'application/octet-stream'
# Return the response
return response
request를 보내는 쪽의 프로그램은 다음과 같다. 역시 chatGPT가 만들어주었다.
import requests
import struct
# Define the binary protocol command and payload
command = struct.pack('6B', 0x01, 0x02, 0x03, 0x04, 0x05, 0x06)
payload = b'hello world'
# Send the binary protocol command and payload to the Flask server
response = requests.post('http://localhost:5000/api', data=command+payload)
# Parse the 6-byte response data
response_data = response.content
response_tuple = struct.unpack('6B', response_data)
print('Response:', response_tuple)
데이터 부분만 약간 수정해서 실제 명령을 보내 보았고,
response 받는 것 까지 잘되는 것을 확인하였다.
이제 python에서 명령에 따라 spi를 호출하기만 하면되니, 일차적인 기술적인 난관 다 해결한 셈이다.
'미니 프로젝트 > 라즈베리파이 REST API for SPI' 카테고리의 다른 글
라즈베리파이 4 UART 연결 테스트 (0) | 2023.07.21 |
---|---|
C와 python 연결하기 - ctypes (0) | 2023.05.09 |
라즈베리파이 3 SPI 테스트 (0) | 2023.05.04 |
라즈베리파이 3 SPI 포트 5 개로 늘리기 (0) | 2023.05.04 |
라즈베리파이 3 UART 연결하기 (0) | 2023.05.04 |