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 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.
3
+
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.
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.
9
+
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:
10
10
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.
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
12
17
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.
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.
20
19
21
20
## Bricks Used
22
21
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.
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.
27
24
28
25
## Hardware and Software Requirements
29
26
@@ -38,152 +35,127 @@ The LED Matrix Painter example uses the following Bricks:
38
35
39
36
## How to Use the Example
40
37
41
-
1.**Run the App**
42
-
Launch the example by clicking the **Run** button from Arduino App Lab.
43
-
44
-
2.**Access the Editor**
45
-
Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000`.
46
-
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.
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
51
55
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.
56
+
## How it Works
55
57
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.
58
+
The LED Matrix Painter consists of three main components working together:
62
59
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.
60
+
-**Web Interface (Frontend)**: An interactive grid editor built with HTML/CSS/JavaScript that sends pixel data to the backend via HTTP API calls.
67
61
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.
62
+
-**Python Backend**: Handles frame storage in a SQLite database, manages frame transformations, and communicates with the Arduino via Router Bridge.
71
63
72
-
## How it Works
64
+
-**Arduino Sketch**: Receives frame data over Router Bridge and displays it on the physical LED matrix using the `Arduino_LED_Matrix` library.
73
65
74
-
The LED Matrix Painter relies on a synchronized data flow between the browser, the Python backend, and the hardware.
75
-
76
-
**High-level data flow:**
66
+
High-level data flow:
77
67
78
68
```
79
-
Web Browser ──► HTTP API ──► Python Backend ──► Router Bridge ──► Arduino Sketch
80
-
│ │
81
-
▼ ▼
82
-
SQLite Database LED Matrix Display
69
+
Web Browser → HTTP API → Python Backend → Router Bridge → Arduino LED Matrix
70
+
↓
71
+
SQLite Database
83
72
```
84
73
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.
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
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
-
```
83
+
### 🔧 Backend (`main.py`)
115
84
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
-
```
85
+
The Python application manages the HTTP API, database operations, and communication with the Arduino.
137
86
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.
87
+
-**`designer = FrameDesigner()`**: Initializes the frame designer utility from `arduino.app_utils`, which provides transformation operations (invert, rotate, flip).
139
88
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
-
```
89
+
-**`store.init_db()`**: Creates the SQLite database and tables for storing frames if they don't exist.
149
90
150
-
### 🔧 Arduino Component (`sketch.ino`)
91
+
-**`ui.expose_api('POST', '/persist_frame', persist_frame)`**: Exposes an HTTP endpoint that saves or updates frames in the database.
151
92
152
-
The sketch is designed to be a passive renderer, accepting commands from the Python backend.
93
+
-**`ui.expose_api('POST', '/load_frame', load_frame)`**: Loads a frame from the database by ID or retrieves the last edited frame.
153
94
154
-
-**Grayscale Setup**: The matrix is initialized with 8-bit grayscale support to allow for varying brightness levels.
95
+
-**`ui.expose_api('GET', '/list_frames', list_frames)`**: Returns all saved frames for display in the sidebar.
155
96
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
-
```
97
+
-**`ui.expose_api('POST', '/play_animation', play_animation)`**: Sends a sequence of frames to the Arduino to play as an animation.
165
98
166
-
-**Drawing**: The `draw` provider accepts a vector of bytes and renders it directly.
99
+
-**`ui.expose_api('POST', '/export_frames', export_frames)`**: Generates C++ code arrays from selected frames for use in Arduino sketches.
167
100
168
-
```cpp
169
-
voiddraw(std::vector<uint8_t> frame) {
170
-
matrix.draw(frame.data());
171
-
}
172
-
```
101
+
-**`Bridge.call("draw", frame_bytes)`**: Sends frame data to the Arduino sketch to update the LED matrix display.
102
+
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.
173
112
174
-
### 🔧 Frontend (`app.js`)
113
+
-**Frame List**: Displays all saved frames in a sidebar with options to load, delete, or reorder them.
175
114
176
-
The JavaScript frontend handles the UI logic and data synchronization.
115
+
-**Animations Mode**: Allows creating and managing animation sequences by dragging frames into animation containers.
177
116
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.
// Unified persist: save to DB and update board together
182
-
function schedulePersist(){
183
-
if (persistTimeout) clearTimeout(persistTimeout);
184
-
persistTimeout = setTimeout(()=> {
185
-
persistFrame();
186
-
persistTimeout = null;
187
-
}, AUTO_PERSIST_DELAY_MS);
188
-
}
119
+
-**Export Modal**: Generates and displays C++ code for selected frames or animations.
120
+
121
+
-**HTTP API calls**: Uses `fetch()` to communicate with the Python backend for all frame operations (save, load, delete, transform, export, play).
122
+
123
+
### 🔧 Hardware (`sketch.ino`)
124
+
125
+
The Arduino code handles LED matrix control and Router Bridge communication.
126
+
127
+
-**`matrix.begin()`**: Initializes the Arduino_LED_Matrix library for controlling the UNO Q LED matrix.
128
+
129
+
-**`matrix.setGrayscaleBits(8)`**: Configures the matrix to accept 8-bit brightness values (0-255) for each pixel.
130
+
131
+
-**`Bridge.begin()`**: Initializes Router Bridge for receiving commands from the Python application.
132
+
133
+
-**`Bridge.provide("draw", draw)`**: Registers the `draw` function to be callable from Python, which accepts frame data and renders it on the matrix.
134
+
135
+
-**`Bridge.provide("play_animation", play_animation)`**: Registers the animation playback function that accepts multiple frames and plays them sequentially.
136
+
137
+
-**`matrix.draw(frame.data())`**: Renders a single frame on the LED matrix using raw byte data.
138
+
139
+
-**`matrix.loadWrapper()` + `matrix.playSequence()`**: Loads an animation sequence and plays it on the LED matrix.
140
+
141
+
## Frame Data Format
142
+
143
+
Frames are stored as 8×13 arrays where each value represents LED brightness (0-255):
144
+
145
+
```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
+
};
152
+
```
153
+
154
+
For animations, frames are stored as `uint32_t` arrays compatible with the Arduino_LED_Matrix library:
0 commit comments