Matrix/API/main.py

423 lines
9.9 KiB
Python
Raw Permalink Normal View History

2023-11-22 15:21:15 +00:00
#!/usr/bin/env python
2024-02-16 08:15:01 +00:00
2023-11-22 15:44:26 +00:00
from deps.samplebase import SampleBase
2023-11-22 15:21:15 +00:00
from rgbmatrix import graphics
2024-02-15 08:27:19 +00:00
from PIL import Image
2024-02-16 06:12:12 +00:00
import base64
import io
2023-11-23 07:15:02 +00:00
2023-11-23 09:07:17 +00:00
from flask import Flask, request, jsonify
2023-11-23 13:31:18 +00:00
from flask_cors import CORS, cross_origin
2024-03-13 12:03:09 +00:00
from dotenv import load_dotenv
2023-11-23 07:49:47 +00:00
from waitress import serve
2024-03-13 12:03:09 +00:00
from pathlib import Path
2024-03-14 13:30:56 +00:00
import os, time, threading, json
2023-11-22 14:41:13 +00:00
2023-11-23 07:15:02 +00:00
2024-03-13 12:03:09 +00:00
env_path = Path('..') / '.env'
load_dotenv(dotenv_path=env_path)
2023-11-23 09:07:17 +00:00
api = Flask(__name__)
2023-11-23 13:31:18 +00:00
cors = CORS(api)
2023-11-23 07:15:02 +00:00
2024-03-14 13:30:56 +00:00
@api.route('/instructions', methods=['POST'])
@cross_origin()
def instructions():
# prepare response data
response = { 'success': True }
try:
global matrix
assert matrix is not None
# receive client data
data = request.form
# try unpacking instruction list
instructions = data.get('instructions')
# parse json data from instructions string
ins_set = json.loads(instructions)
# call respective matrix methods with corresponding data
for ins in ins_set:
if ins['endpoint'] == 'upload':
url = ins['url']
matrix.set_image(url)
elif ins['endpoint'] == 'image':
x = int(ins['x'])
y = int(ins['y'])
matrix.display_image(x, y)
elif ins['endpoint'] == 'text':
x = int(ins['x'])
y = int(ins['y'])
matrix.text(x, y, ins['text'])
elif ins['endpoint'] == 'pixel':
x = int(ins['x'])
y = int(ins['y'])
matrix.pixel(x, y)
elif ins['endpoint'] == 'circle':
x = int(ins['x'])
y = int(ins['y'])
r = int(ins['r'])
matrix.circle(x, y, r)
elif ins['endpoint'] == 'rectangle':
x = int(ins['x'])
y = int(ins['y'])
w = int(ins['w'])
h = int(ins['h'])
matrix.rectangle(x, y, w, h)
elif ins['endpoint'] == 'line':
x1 = int(ins['x1'])
y1 = int(ins['y1'])
x2 = int(ins['x2'])
y2 = int(ins['y2'])
matrix.line(x1, y1, x2, y2)
elif ins['endpoint'] == 'color':
r = int(ins['r'])
g = int(ins['g'])
b = int(ins['b'])
matrix.set_color(r, g, b)
2024-03-14 13:30:56 +00:00
elif ins['endpoint'] == 'clear':
matrix.clear()
elif ins['endpoint'] == 'update':
matrix.update()
except Exception as e:
# error handling
print(e)
response['success'] = False
# respond to client
return jsonify(response)
2024-02-15 08:43:38 +00:00
@api.route('/upload', methods=['POST'])
2024-02-15 08:27:19 +00:00
@cross_origin()
def set_image():
# prepare response data
response = { 'success': True }
try:
global matrix
assert matrix is not None
# receive client data
data = request.form
# try unpacking text and x,y coordinates
url = data.get('url')
# call matrix method with data
matrix.set_image(url)
except Exception as e:
# error handling
print(e)
response['success'] = False
# respond to client
return jsonify(response)
2024-02-15 08:43:38 +00:00
@api.route('/image', methods=['POST'])
2024-02-15 08:27:19 +00:00
@cross_origin()
def display_image():
# prepare response data
response = { 'success': True }
try:
global matrix
assert matrix is not None
# receive client data
data = request.form
# try unpacking x,y coordinates
x_coord = int(data.get('x'))
y_coord = int(data.get('y'))
# call matrix method with data
2024-02-16 06:11:50 +00:00
matrix.display_image(x_coord, y_coord)
2024-02-15 08:27:19 +00:00
except Exception as e:
# error handling
print(e)
response['success'] = False
# respond to client
return jsonify(response)
2023-11-23 09:07:41 +00:00
@api.route('/text', methods=['POST'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:07:41 +00:00
def display_text():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:07:41 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 09:07:41 +00:00
2023-11-23 10:45:56 +00:00
# receive client data
2023-11-24 06:06:43 +00:00
data = request.form
2023-11-23 10:45:56 +00:00
# try unpacking text and x,y coordinates
2023-11-23 09:07:41 +00:00
text = data.get('text')
2023-11-24 06:06:43 +00:00
x_coord = int(data.get('x'))
y_coord = int(data.get('y'))
2023-11-23 09:07:41 +00:00
2023-11-23 10:45:56 +00:00
# call matrix method with data
2023-11-23 09:07:41 +00:00
matrix.text(x_coord, y_coord, text)
2023-11-23 09:44:57 +00:00
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:44:57 +00:00
print(e)
2023-11-23 09:07:41 +00:00
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:07:41 +00:00
return jsonify(response)
2023-11-23 09:46:15 +00:00
@api.route('/pixel', methods=['POST'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:46:15 +00:00
def set_pixel():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:46:15 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 09:46:15 +00:00
2023-11-23 10:45:56 +00:00
# receive client data
2023-11-24 06:06:43 +00:00
data = request.form
2023-11-23 10:45:56 +00:00
# try unpacking x,y coordinates
2023-11-24 06:06:43 +00:00
x_coord = int(data.get('x'))
y_coord = int(data.get('y'))
2023-11-23 09:46:15 +00:00
2023-11-23 10:45:56 +00:00
# call matrix method with data
2023-11-23 09:46:15 +00:00
matrix.pixel(x_coord, y_coord)
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:46:15 +00:00
print(e)
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:46:15 +00:00
return jsonify(response)
2023-11-23 09:47:40 +00:00
@api.route('/circle', methods=['POST'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:47:40 +00:00
def draw_circle():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:47:40 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 09:47:40 +00:00
2023-11-23 10:45:56 +00:00
# receive client data
2023-11-24 06:06:43 +00:00
data = request.form
2023-11-23 10:45:56 +00:00
# try unpacking radius and x,y coordinates
2023-11-24 06:06:43 +00:00
radius = int(data.get('r'))
x_coord = int(data.get('x'))
y_coord = int(data.get('y'))
2023-11-23 09:47:40 +00:00
2023-11-23 10:45:56 +00:00
# call matrix method with data
2023-11-23 09:47:40 +00:00
matrix.circle(x_coord, y_coord, radius)
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:47:40 +00:00
print(e)
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:47:40 +00:00
return jsonify(response)
2023-11-23 09:48:19 +00:00
@api.route('/rectangle', methods=['POST'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:48:19 +00:00
def draw_rectangle():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:48:19 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 09:48:19 +00:00
2023-11-23 10:45:56 +00:00
# receive client data
2023-11-24 06:06:43 +00:00
data = request.form
2023-11-23 10:45:56 +00:00
# try unpacking rectangle width and height
2023-11-24 06:06:43 +00:00
width = int(data.get('w'))
height = int(data.get('h'))
2023-11-23 10:45:56 +00:00
# try unpacking x,y coordinates
2023-11-24 06:06:43 +00:00
x_coord = int(data.get('x'))
y_coord = int(data.get('y'))
2023-11-23 09:48:19 +00:00
2023-11-23 10:45:56 +00:00
# call matrix method with data
2023-11-23 09:48:19 +00:00
matrix.rectangle(x_coord, y_coord, width, height)
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:48:19 +00:00
print(e)
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:48:19 +00:00
return jsonify(response)
@api.route('/line', methods=['POST'])
@cross_origin()
def draw_line():
# prepare response data
response = { 'success': True }
try:
global matrix
assert matrix is not None
# receive client data
data = request.form
# try unpacking x,y coordinates
x1 = int(data.get('x1'))
y1 = int(data.get('y1'))
x2 = int(data.get('x2'))
y2 = int(data.get('y2'))
# call matrix method with data
matrix.line(x1, y1, x2, y2)
except Exception as e:
# error handling
print(e)
response['success'] = False
# respond to client
return jsonify(response)
2023-11-23 09:46:43 +00:00
@api.route('/color', methods=['POST'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:46:43 +00:00
def set_color():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:46:43 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 09:46:43 +00:00
2023-11-23 10:45:56 +00:00
# receive client data
2023-11-24 06:06:43 +00:00
data = request.form
2023-11-23 10:45:56 +00:00
# try unpacking red, green and blue color values
2023-11-24 06:06:43 +00:00
red = int(data.get('r'))
green = int(data.get('g'))
blue = int(data.get('b'))
2023-11-23 09:46:43 +00:00
2023-11-23 10:45:56 +00:00
# call matrix method with data
2023-11-23 09:46:43 +00:00
matrix.set_color(red, green, blue)
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:46:43 +00:00
print(e)
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:46:43 +00:00
return jsonify(response)
2023-11-23 09:49:03 +00:00
@api.route('/clear', methods=['GET'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 13:03:55 +00:00
def clear_canvas():
2023-11-23 10:45:56 +00:00
# prepare response data
2023-11-23 09:49:03 +00:00
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-23 10:45:56 +00:00
2023-11-24 06:06:43 +00:00
# clear matrix canvas
2023-11-23 09:49:03 +00:00
matrix.clear()
except Exception as e:
2023-11-23 10:45:56 +00:00
# error handling
2023-11-23 09:49:03 +00:00
print(e)
response['success'] = False
2024-02-15 08:27:05 +00:00
# respond to client
2023-11-23 09:49:03 +00:00
return jsonify(response)
2023-11-23 09:07:41 +00:00
@api.route('/update', methods=['GET'])
2023-11-23 13:31:18 +00:00
@cross_origin()
2023-11-23 09:07:41 +00:00
def update_matrix():
response = { 'success': True }
try:
global matrix
2024-02-15 08:27:05 +00:00
assert matrix is not None
2023-11-24 06:06:43 +00:00
# swap matrix canvas
2023-11-23 09:07:41 +00:00
matrix.update()
2023-11-23 09:44:57 +00:00
except Exception as e:
print(e)
2023-11-23 09:07:41 +00:00
response['success'] = False
2023-11-23 10:45:56 +00:00
# respond to client
2023-11-23 09:07:41 +00:00
return jsonify(response)
2023-11-23 07:49:47 +00:00
2023-11-23 07:15:02 +00:00
2023-11-23 10:45:56 +00:00
# derived class to access rgb-led-matrix
2023-11-23 09:07:17 +00:00
class Matrix(SampleBase):
2023-11-22 15:22:19 +00:00
def __init__(self, *args, **kwargs):
2023-11-23 09:07:17 +00:00
super(Matrix, self).__init__(*args, **kwargs)
self.parser.set_defaults(led_rows=int(os.getenv('PUBLIC_LED_WIDTH', 64)))
self.parser.set_defaults(led_cols=int(os.getenv('PUBLIC_LED_HEIGHT', 64)))
self.parser.set_defaults(led_chain=int(os.getenv('PUBLIC_LED_CHAIN', 1)))
self.parser.set_defaults(led_parallel=int(os.getenv('PUBLIC_LED_PARALLEL', 1)))
2023-11-22 14:41:13 +00:00
2023-11-23 10:45:56 +00:00
# run display program
2023-11-22 15:22:19 +00:00
def run(self):
2023-11-23 10:45:56 +00:00
# initialize font
2023-11-23 07:49:47 +00:00
self.font = graphics.Font()
self.font.LoadFont("deps/fonts/9x18B.bdf")
2023-11-23 10:45:56 +00:00
# initialize color
2023-11-23 07:49:47 +00:00
self.color = graphics.Color(255, 255, 255)
2024-02-15 08:27:19 +00:00
# initialize image
self.image = None
2023-11-23 09:07:17 +00:00
2023-11-23 10:45:56 +00:00
# initialize canvas
2023-11-23 07:49:47 +00:00
self.canvas = self.matrix.CreateFrameCanvas()
2023-11-23 09:07:17 +00:00
self.canvas.Clear()
2023-11-22 14:41:13 +00:00
2023-11-23 10:45:56 +00:00
# wait in idle
2023-11-22 15:21:15 +00:00
while True:
2023-11-23 07:49:47 +00:00
time.sleep(.05)
2023-11-23 07:15:02 +00:00
2023-11-23 10:45:56 +00:00
# clear canvas
2023-11-23 09:44:57 +00:00
def clear(self):
self.canvas.Clear()
2023-11-23 10:45:56 +00:00
# swap canvas with buffer
2023-11-23 07:49:47 +00:00
def update(self):
self.canvas = self.matrix.SwapOnVSync(self.canvas)
2023-11-23 09:44:57 +00:00
self.clear()
2023-11-23 09:07:17 +00:00
2023-11-23 10:45:56 +00:00
# set current color
2023-11-24 06:06:43 +00:00
def set_color(self, r: int, g: int, b: int):
2023-11-23 09:46:15 +00:00
self.color = graphics.Color(r, g, b)
2023-11-23 10:45:56 +00:00
# set specified pixel to current color
2023-11-24 06:06:43 +00:00
def pixel(self, x: int, y: int):
2023-11-23 09:46:15 +00:00
self.canvas.SetPixel(x, y, self.color.red, self.color.green, self.color.blue)
2023-11-23 10:45:56 +00:00
# display text at position with current color
2023-11-24 06:06:43 +00:00
def text(self, x: int, y: int, t: int):
2023-11-23 09:07:17 +00:00
graphics.DrawText(self.canvas, self.font, x*9, (y+1)*18, self.color, t)
2023-11-22 14:41:13 +00:00
2023-11-23 10:45:56 +00:00
# display circle at position with radius in current color
2023-11-24 06:06:43 +00:00
def circle(self, x: int, y: int, r: int):
2023-11-24 06:09:04 +00:00
graphics.DrawCircle(self.canvas, x, y, r, self.color)
2023-11-23 09:47:40 +00:00
2023-11-23 10:45:56 +00:00
# display rectangle at position with dimensions in current color
2023-11-24 06:06:43 +00:00
def rectangle(self, x: int, y: int, w: int, h: int):
2023-11-23 10:45:56 +00:00
# loop through each point in dimensions
2023-11-23 09:48:19 +00:00
for i in range(w):
for j in range(h):
2023-11-23 10:45:56 +00:00
# set next pixel in rectangle
2023-11-23 09:48:19 +00:00
self.canvas.SetPixel(x+i, y+j, self.color.red, self.color.green, self.color.blue)
# display line from (x1,y1) to (x2,y2) in current color
def line(self, x1: int, y1: int, x2: int, y2: int):
graphics.DrawLine(self.canvas, x1, y1, x2, y2, self.color)
2024-02-15 08:27:19 +00:00
# set current image
def set_image(self, url: str):
2024-02-16 06:12:12 +00:00
_, data = url.split(',')
data = base64.b64decode(data)
self.image = Image.open(io.BytesIO(data)).convert('RGB')
2024-02-15 08:27:19 +00:00
2024-02-15 08:31:34 +00:00
# display image at position with dimensions in current color
2024-02-16 06:11:50 +00:00
def display_image(self, x: int, y: int):
if self.image is None: return
2024-02-15 08:27:19 +00:00
# set image at position
self.canvas.SetImage(self.image, x, y)
2023-11-22 15:21:15 +00:00
2023-11-23 10:45:56 +00:00
# initialize global matrix variable
2023-11-23 09:07:17 +00:00
matrix = None
2023-11-22 15:21:15 +00:00
if __name__ == "__main__":
2023-11-23 10:45:56 +00:00
# set matrix to instance
2023-11-23 09:07:17 +00:00
matrix = Matrix()
2023-11-23 10:45:56 +00:00
# run rest api in thread, serving with 'waitress'
2023-11-23 09:07:17 +00:00
threading.Thread(target=lambda: serve(api, host="0.0.0.0", port=8080)).start()
2023-11-23 07:15:02 +00:00
2023-11-23 10:45:56 +00:00
# help menu on call
2023-11-23 09:07:17 +00:00
if not matrix.process():
matrix.print_help()