You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The **LED Matrix Painter** example provides a web-based tool for designing frames and animations for the Arduino UNO Q 8×13 LED matrix. You can create individual frames, organize them into animations, preview them in real-time on the board, and export them as C++ code.
3
+
The **LED Matrix Painter** example provides a web-based interface to draw, animate, and control the built-in LED Matrix of the Arduino UNO Q in real-time. It features a pixel editor with 8-bit brightness control, database storage for your designs, and a code generator to export your frames as ready-to-use C++ code.
This example allows you to design LED matrix frames using an interactive web interface. Each frame can have custom brightness levels (0-7) for each LED pixel. You can:
9
+
This App allows you to design visuals for the 8x13 LED matrix directly from your browser. It uses the `web_ui` Brick to host a graphical editor where you can paint individual pixels, adjust their brightness, and apply transformations like flipping or rotating. Every change you make in the browser is immediately reflected on the physical board.
10
10
11
-
-**Design frames** with pixel-by-pixel control using an interactive grid
12
-
-**Preview in real-time** on the Arduino UNO Q LED matrix
13
-
-**Save and organize** multiple frames with a persistent database
14
-
-**Create animations** by sequencing multiple frames together
15
-
-**Export code** as C++ arrays ready to use in your Arduino sketches
16
-
-**Transform frames** with operations like invert, rotate, and flip
11
+
The application uses the `dbstorage_sqlstore` Brick to automatically save your work in a local database. You can create multiple frames, organize them into animations, and use the "Code panel" to see the generated C++ code in real-time.
17
12
18
-
The application uses the Router Bridge to communicate between the web interface (running on Linux) and the Arduino sketch (running on the microcontroller), enabling real-time updates to the physical LED matrix.
13
+
Key features include:
14
+
-**Real-time Control:** Drawing on the web grid updates the UNO Q matrix instantly.
15
+
-**Grayscale Control:** 8 brightness presets (0-7) for intuitive pixel control, with full 8-bit precision (0-255) supported at the hardware level.
16
+
-**Persistent Storage:** Frames are automatically saved to a database, allowing you to build complex animations over time.
17
+
-**Transformation Tools:** Invert, rotate, or flip designs with a single click.
18
+
-**Animation Mode:** Sequence frames to create animations and preview them on the board.
19
+
-**Code Export:** Generate `uint32_t` arrays compatible with the `Arduino_LED_Matrix` library for use in standalone sketches.
19
20
20
21
## Bricks Used
21
22
22
-
-`web_ui`: Provides the web server and HTTP API endpoints for the interactive frame designer interface.
23
-
-`dbstorage_sqlstore` (implicit): Stores frame data persistently in a SQLite database.
23
+
The LED Matrix Painter example uses the following Bricks:
24
+
25
+
-`web_ui`: Brick to create the interactive grid editor and manage API endpoints.
26
+
-`dbstorage_sqlstore`: Brick to persist frames and animation sequences using a SQLite database.
24
27
25
28
## Hardware and Software Requirements
26
29
@@ -35,127 +38,152 @@ The application uses the Router Bridge to communicate between the web interface
35
38
36
39
## How to Use the Example
37
40
38
-
1. Launch the App by clicking the **Play** button in the top-right corner. Wait until the App has launched.
39
-
2.**Design a frame:**
40
-
- Click on individual pixels in the 8×13 grid to toggle them on/off
41
-
- Use the brightness slider to adjust LED intensity (0-7)
42
-
- Click on pixels with different brightness values to paint with varying intensities
43
-
3.**Save your frame:**
44
-
- Click the **Save Frame** button to persist the current design
45
-
- Frames are automatically saved to a database and appear in the sidebar
46
-
4.**Create animations:**
47
-
- Save multiple frames
48
-
- Switch to **Animations** mode in the sidebar
49
-
- Create a new animation and add frames to it
50
-
- Use **Play** to preview the animation on the board
51
-
5.**Export code:**
52
-
- Select the frames or animations you want to export
53
-
- Click **Export** to generate C++ code
54
-
- Copy the generated arrays into your Arduino sketch
55
-
56
-
## How it Works
57
-
58
-
The LED Matrix Painter consists of three main components working together:
59
-
60
-
-**Web Interface (Frontend)**: An interactive grid editor built with HTML/CSS/JavaScript that sends pixel data to the backend via HTTP API calls.
61
-
62
-
-**Python Backend**: Handles frame storage in a SQLite database, manages frame transformations, and communicates with the Arduino via Router Bridge.
63
-
64
-
-**Arduino Sketch**: Receives frame data over Router Bridge and displays it on the physical LED matrix using the `Arduino_LED_Matrix` library.
65
-
66
-
High-level data flow:
67
-
68
-
```
69
-
Web Browser → HTTP API → Python Backend → Router Bridge → Arduino LED Matrix
70
-
↓
71
-
SQLite Database
72
-
```
73
-
74
-
The workflow:
75
-
1. User edits a frame in the web interface
76
-
2. Changes are sent to Python backend via HTTP POST
77
-
3. Backend validates and stores the frame in SQLite
78
-
4. Backend sends frame data to Arduino via Bridge
79
-
5. Arduino sketch renders the frame on the LED matrix
80
-
81
-
## Understanding the Code
82
-
83
-
### 🔧 Backend (`main.py`)
84
-
85
-
The Python application manages the HTTP API, database operations, and communication with the Arduino.
86
-
87
-
-**`designer = FrameDesigner()`**: Initializes the frame designer utility from `arduino.app_utils`, which provides transformation operations (invert, rotate, flip).
88
-
89
-
-**`store.init_db()`**: Creates the SQLite database and tables for storing frames if they don't exist.
41
+
1.**Run the App**
42
+
Launch the example by clicking the **Run** button from Arduino App Lab.
90
43
91
-
-**`ui.expose_api('POST', '/persist_frame', persist_frame)`**: Exposes an HTTP endpoint that saves or updates frames in the database.
44
+
2.**Access the Editor**
45
+
Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000`.
92
46
93
-
-**`ui.expose_api('POST', '/load_frame', load_frame)`**: Loads a frame from the database by ID or retrieves the last edited frame.
47
+
3.**Draw Frames**
48
+
-**Paint:** Click any cell in the central grid to turn it on.
49
+
-**Adjust Brightness:** Click an active cell again (or hover/wait) to open the floating slider and set the brightness level (0-7).
50
+
-**Preview:** Observe the UNO Q; the matrix updates instantly as you draw.
94
51
95
-
-**`ui.expose_api('GET', '/list_frames', list_frames)`**: Returns all saved frames for display in the sidebar.
52
+
4.**Use the Design Tools**
53
+
-**Transform:** Use the **Tools** panel on the left to **Flip Vertically/Horizontally**, **Rotate 180°**, **Invert Matrix** (negative), or **Invert Draw** (brightness).
54
+
-**Clear:** Use the **Clear Frame** button above the grid to reset the canvas.
96
55
97
-
-**`ui.expose_api('POST', '/play_animation', play_animation)`**: Sends a sequence of frames to the Arduino to play as an animation.
56
+
5.**Manage Frames (Bottom Panel)**
57
+
-**Auto-save:** Your work is saved to the database automatically.
58
+
-**Create:** Click the **+** button to add a new empty frame.
59
+
-**Edit Details:** Assign a **Name** and **Duration** (in milliseconds) for each frame using the inputs above the frame list.
60
+
-**Reorder:** Drag and drop frame thumbnails to change their sequence.
61
+
-**Load/Delete:** Use the **Load** and **Del** buttons on each thumbnail to switch between frames or remove them.
98
62
99
-
-**`ui.expose_api('POST', '/export_frames', export_frames)`**: Generates C++ code arrays from selected frames for use in Arduino sketches.
63
+
6.**Create Animations**
64
+
- Switch the mode to **Animations** using the radio buttons in the bottom panel.
65
+
- Select multiple frames by clicking on their thumbnails (they will highlight).
66
+
- Click the **Play Animation** button below the grid to preview the sequence on the board.
100
67
101
-
-**`Bridge.call("draw", frame_bytes)`**: Sends frame data to the Arduino sketch to update the LED matrix display.
68
+
7.**Export Code**
69
+
- Toggle the **Code panel** switch in the top right header to view the C++ code for the current frame or animation in real-time.
70
+
- Click the **Export .h** button to download a header file containing your selected designs, ready to be included in an Arduino sketch.
102
71
103
-
-**`AppFrame` class**: Custom extension of `arduino.app_utils.Frame` that adds metadata like frame name, position, duration, and database persistence methods.
104
-
105
-
### 💻 Frontend (`app.js` + `index.html`)
106
-
107
-
The web interface provides an interactive pixel grid editor and frame management tools.
108
-
109
-
-**Pixel Grid**: An 8×13 canvas that responds to mouse clicks and drag operations for painting pixels.
110
-
111
-
-**Brightness Control**: A slider (0-7) that controls the current brush brightness level.
112
-
113
-
-**Frame List**: Displays all saved frames in a sidebar with options to load, delete, or reorder them.
114
-
115
-
-**Animations Mode**: Allows creating and managing animation sequences by dragging frames into animation containers.
The LED Matrix Painter relies on a synchronized data flow between the browser, the Python backend, and the hardware.
118
75
119
-
-**Export Modal**: Generates and displays C++ code for selected frames or animations.
76
+
**High-level data flow:**
120
77
121
-
-**HTTP API calls**: Uses `fetch()` to communicate with the Python backend for all frame operations (save, load, delete, transform, export, play).
78
+
```
79
+
Web Browser ──► HTTP API ──► Python Backend ──► Router Bridge ──► Arduino Sketch
80
+
│ │
81
+
▼ ▼
82
+
SQLite Database LED Matrix Display
83
+
```
122
84
123
-
### 🔧 Hardware (`sketch.ino`)
85
+
1.**Web Interface**: The `app.js` script captures clicks on the grid. It debounces these events and sends the pixel data to the backend via the `/persist_frame` endpoint.
86
+
2.**Python Backend**:
87
+
***Data Model**: The `AppFrame` class normalizes the data, converting between frontend JSON, database records, and hardware byte arrays.
88
+
***Persistence**: The `store.py` module uses `SQLStore` to save the frame data to a `frames` table in a SQLite database.
89
+
***Bridge**: The `main.py` script sends the raw byte array to the board via `Bridge.call("draw", frame_bytes)`.
90
+
3.**Arduino Sketch**: The sketch receives the raw byte data and uses the `Arduino_LED_Matrix` library to render the grayscale image.
124
91
125
-
The Arduino code handles LED matrix control and Router Bridge communication.
92
+
## Understanding the Code
126
93
127
-
-**`matrix.begin()`**: Initializes the Arduino_LED_Matrix library for controlling the UNO Q LED matrix.
The Python backend manages the application logic, database, and hardware communication.
97
+
98
+
-**Data Model (`app_frame.py`)**: The `AppFrame` class is the core data structure that acts as a bridge between the different components. It extends the base `Frame` class to add application-specific metadata like `id`, `name`, `position`, and `duration`. It handles three distinct data contracts:
99
+
-**API Contract**: `to_json()` / `from_json()` formats data for the web frontend.
100
+
-**Database Contract**: `to_record()` / `from_record()` formats data for `SQLStore` storage.
101
+
-**Hardware Contract**: `to_board_bytes()` packs pixels into the specific byte format expected by the Arduino sketch.
102
+
103
+
```python
104
+
classAppFrame(Frame):
105
+
defto_record(self) -> dict:
106
+
"""Convert to a database record dict for storage."""
107
+
return {
108
+
"id": self.id,
109
+
"name": self.name,
110
+
"rows": json.dumps(self.arr.tolist()), # Serialize pixels to JSON string
111
+
"brightness_levels": int(self.brightness_levels),
112
+
# ...
113
+
}
114
+
```
128
115
129
-
-**`matrix.setGrayscaleBits(8)`**: Configures the matrix to accept 8-bit brightness values (0-255) for each pixel.
116
+
-**Initialization**:
117
+
-`designer = FrameDesigner()`: Initializes the frame designer utility from `arduino.app_utils`, which provides the logic for transformation operations (invert, rotate, flip).
118
+
-`store.init_db()`: Creates the SQLite database and tables for storing frames if they don't exist.
119
+
120
+
-**API Endpoints**: The backend exposes several HTTP endpoints using `ui.expose_api` to handle frontend requests:
121
+
-`POST /persist_frame`: Saves or updates frames in the database and updates the board.
122
+
-`POST /load_frame`: Loads a specific frame by ID or retrieves the last edited frame.
123
+
-`GET /list_frames`: Returns all saved frames to populate the bottom panel.
124
+
-`POST /play_animation`: Sends a sequence of frames to the Arduino to play as an animation.
125
+
-`POST /transform_frame`: Applies geometric transformations to the pixel data.
126
+
-`POST /export_frames`: Generates the C++ header file content.
127
+
128
+
-**Hardware Update**: The `apply_frame_to_board` function sends the visual data to the microcontroller via the Bridge.
129
+
130
+
```python
131
+
# main.py
132
+
defapply_frame_to_board(frame: AppFrame):
133
+
"""Send frame bytes to the Arduino board."""
134
+
frame_bytes = frame.to_board_bytes()
135
+
Bridge.call("draw", frame_bytes)
136
+
```
130
137
131
-
-**`Bridge.begin()`**: Initializes Router Bridge for receiving commands from the Python application.
138
+
-**Code Generation**: The `AppFrame` class generates the C++ code displayed in the UI. It formats the internal array data into `uint32_t` hex values.
132
139
133
-
-**`Bridge.provide("draw", draw)`**: Registers the `draw` function to be callable from Python, which accepts frame data and renders it on the matrix.
140
+
```python
141
+
# app_frame.py
142
+
defto_c_string(self) -> str:
143
+
c_type ="uint32_t"
144
+
parts = [f"const {c_type}{self.name}[] = {{"]
145
+
# Converts pixel brightness data to uint32_t hex format
146
+
parts.append("};")
147
+
return"\n".join(parts)
148
+
```
134
149
135
-
-**`Bridge.provide("play_animation", play_animation)`**: Registers the animation playback function that accepts multiple frames and plays them sequentially.
150
+
### 🔧 Arduino Component (`sketch.ino`)
136
151
137
-
-**`matrix.draw(frame.data())`**: Renders a single frame on the LED matrix using raw byte data.
152
+
The sketch is designed to be a passive renderer, accepting commands from the Python backend.
138
153
139
-
-**`matrix.loadWrapper()` + `matrix.playSequence()`**: Loads an animation sequence and plays it on the LED matrix.
154
+
-**Grayscale Setup**: The matrix is initialized with 8-bit grayscale support to allow for varying brightness levels.
140
155
141
-
## Frame Data Format
156
+
```cpp
157
+
voidsetup() {
158
+
matrix.begin();
159
+
// configure grayscale bits to 8 so the display can accept 0..255 brightness
160
+
matrix.setGrayscaleBits(8);
161
+
Bridge.begin();
162
+
// ...
163
+
}
164
+
```
142
165
143
-
Frames are stored as 8×13 arrays where each value represents LED brightness (0-255):
166
+
-**Drawing**: The `draw` provider accepts a vector of bytes and renders it directly.
144
167
145
168
```cpp
146
-
// Example frame in C++ format
147
-
constuint8_t frame[][12] = {
148
-
{255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255},
149
-
{0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0},
150
-
// ... 6 more rows
151
-
};
169
+
voiddraw(std::vector<uint8_t> frame) {
170
+
matrix.draw(frame.data());
171
+
}
152
172
```
153
173
154
-
For animations, frames are stored as `uint32_t` arrays compatible with the Arduino_LED_Matrix library:
The JavaScript frontend handles the UI logic and data synchronization.
177
+
178
+
- **Auto-Persist**: To provide a responsive experience, changes are saved automatically after a short delay (debounce), updating both the database and the board simultaneously.
179
+
180
+
```javascript
181
+
// Unified persist: save to DB and update board together
0 commit comments