Rate Limits / Live updating image

Im just doing some personal projects for fun and have a tidbyt that was given to me. I wanted to use a gyroscope input to display a rotating image on the tidbyt. I think Im running into rate limitations of the tidbyt api and am wondering if there is a way around this. I dont really need to use any tidbyt servers if there is a way to directly send a rendered image to the tidbyt, but am unsure if that is possible. I considered trying tidbyt plus, but wasnt sure if that would change rate limitations with a private app, or if a private app would even function for this purpose.

Right now I was just doing this from python and not using gyroscope input, but that is still my end goal. Any ideas?

import requests
from PIL import Image, ImageDraw
from io import BytesIO
import base64
import time, math
import numpy as np

Replace with your Tidbyt API key and device ID

API_KEY = ‘MY-API-KEY’
DEVICE_ID = ‘MY-DEVICE-ID’

Tidbyt API endpoint

URL = f’https://api.tidbyt.com/v0/devices/{DEVICE_ID}/push

Function to apply perspective projection to 3D coordinates

def project_3d_to_2d(x, y, z, viewer_distance=5):
factor = 1 #viewer_distance / (viewer_distance + z) # Simple perspective projection
x2d = int(x * factor * 10 + 32) # Scaling and centering the projection
y2d = int(y * factor * 10 + 16) # Scaling and centering the projection
return (x2d, y2d)

Function to create an image with projected 3D vertices

def create_dynamic_image(vertices_3d):
img = Image.new(‘RGB’, (64, 32), color=(0, 0, 0)) # Black background
draw = ImageDraw.Draw(img)

# Convert 3D vertices to 2D
projected_vertices = []
for i, vertex in enumerate(vertices_3d):
    x, y, z = vertex[0]  # Extract coordinates
    connections = vertex[1]  # Extract connections
    projected = project_3d_to_2d(x, y, z)
    projected_vertices.append((projected, connections, z))  # Keep z for depth

# Draw lines between connected vertices, considering depth
for idx, ((x1, y1), connections, z1) in enumerate(projected_vertices):
    for connection_idx in connections:
        (x2, y2), _, z2 = projected_vertices[connection_idx]
        # Draw a fainter line if it's further away (z1 and z2 are large)
        intensity = max(0, min(255, 255 - int((z1 + z2) * 10)))  # Adjust shading based on depth
        draw.line((x1, y1, x2, y2), fill=(intensity, intensity, intensity))

return img

Define rotation matrices

def rotation_matrix_y(theta):
return np.array([
[np.cos(theta), 0, np.sin(theta)],
[0, 1, 0],
[-np.sin(theta), 0, np.cos(theta)]
])

def rotation_matrix_x(theta):
return np.array([
[1, 0, 0],
[0, np.cos(theta), -np.sin(theta)],
[0, np.sin(theta), np.cos(theta)]
])

def rotation_matrix_z(theta):
return np.array([
[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]
])

Function to upload the image to Tidbyt

def upload_dynamic_content(img):
# Convert the image to PNG format in memory (using BytesIO)
buffered = BytesIO()
img.save(buffered, format=“PNG”)
img_bytes = buffered.getvalue()

# Prepare headers and payload
headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Content-Type': 'application/json'
}

img_base64 = base64.b64encode(img_bytes).decode('utf-8')

payload = {
    'image': img_base64,
    'background': False
}

response = requests.post(URL, headers=headers, json=payload)

if response.status_code == 200:
    print("Dynamic content uploaded successfully!")
else:
    print(f"Failed to upload dynamic content. Status code: {response.status_code}")
    print(response.text)

Cube vertices in 3D space with connections, using NumPy arrays

Each tuple is (x, y, z, [connected_vertices])

vertices_3d = [
[np.array([-1, -1, -1]), [1, 3, 4]], # Vertex 0
[np.array([ 1, -1, -1]), [0, 2, 5]], # Vertex 1
[np.array([ 1, 1, -1]), [1, 3, 6]], # Vertex 2
[np.array([-1, 1, -1]), [0, 2, 7]], # Vertex 3
[np.array([-1, -1, 1]), [0, 5, 7]], # Vertex 4
[np.array([ 1, -1, 1]), [1, 4, 6]], # Vertex 5
[np.array([ 1, 1, 1]), [2, 5, 7]], # Vertex 6
[np.array([-1, 1, 1]), [3, 4, 6]] # Vertex 7
]

Rotation angle (in radians)

theta = np.radians(5)
Rx = rotation_matrix_x(theta)
Ry = rotation_matrix_y(theta)
Rz = rotation_matrix_z(theta)

Render and upload the cube projection with rotations

while True:
# Apply rotations to all vertices
for i in range(len(vertices_3d)):
vertices_3d[i][0] = np.dot(Rx, vertices_3d[i][0]) # Rotate around X-axis
vertices_3d[i][0] = np.dot(Ry, vertices_3d[i][0]) # Rotate around Y-axis
vertices_3d[i][0] = np.dot(Rz, vertices_3d[i][0]) # Rotate around Z-axis

# Create the image and upload it
img = create_dynamic_image(vertices_3d)
upload_dynamic_content(img)
time.sleep(1)  # Update every second

to get around api restrictions by bypassing it directly you would need to flash custom firmware which would then disable any other tidbyt apps you want to run.