Skip to content

Commit 6026f5f

Browse files
Add configuration UI (#158)
* Initial project template * Fix EOF * Simplify * Test * Fix * Improve Screens * Add placeholder Readme * Remove unused imports * Fix CWD * Fix target selection * Misc improvements * WIP compile screen * Update * Fix command * Finish compile screen * Added comments and improvements * Run on task * Make style a bit more Arduino-esque * Add CLI arguments * Small improvements * Rename * Add custom widgets * Fix widgets * Add remaining settings * Improve style * Improve compilation screen * Handle exception * Add no copy argument * Replace "arch" with "uname -m" * Fix copy argument * Fix arg message * Fix chdir * Improve header * Properly kill subprocess * Fix compilation issues * Hide setting depending on switch state * QoL improvements * Improve style * Add python version check * Separate main menu screen * Fix quit and improve logs * Propagate exit code * Rename quit to exit for consistency * Add readme * Improve Readme * Add keybindings * Improve readme * Revert "Merge branch 'bugfix/arch_cmd' into feature/config_ui" This reverts commit 31dbd36, reversing changes made to 2d8e462. * Target list based on JSON and support for any combination of targets * Improve documentation * Add note to the documentation * Fix copy after compilation * Fix bugs * Improve documentation --------- Co-authored-by: me-no-dev <[email protected]> Co-authored-by: Me No Dev <[email protected]>
1 parent 4ec4d25 commit 6026f5f

File tree

9 files changed

+1039
-0
lines changed

9 files changed

+1039
-0
lines changed

Diff for: README.md

+26
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,32 @@ git clone https://github.com/espressif/esp32-arduino-lib-builder
1212
cd esp32-arduino-lib-builder
1313
./build.sh
1414
```
15+
16+
### Using the User Interface
17+
18+
You can more easily build the libraries using the user interface found in the `tools/config_editor/` folder.
19+
It is a Python script that allows you to select and edit the options for the libraries you want to build.
20+
The script has mouse support and can also be pre-configured using the same command line arguments as the `build.sh` script.
21+
For more information and troubleshooting, please refer to the [UI README](tools/config_editor/README.md).
22+
23+
To use it, follow these steps:
24+
25+
1. Make sure you have the required dependencies installed:
26+
- Python 3.9 or later
27+
- The [Textual](https://github.com/textualize/textual/) library
28+
- All the dependencies listed in the previous section
29+
30+
2. Execute the script `tools/config_editor/app.py` from any folder. It will automatically detect the path to the root of the repository.
31+
32+
3. Configure the compilation and ESP-IDF options as desired.
33+
34+
4. Click on the "Compile Static Libraries" button to start the compilation process.
35+
36+
5. The script will show the compilation output in a new screen. Note that the compilation process can take many hours, depending on the number of libraries selected and the options chosen.
37+
38+
6. If the compilation is successful and the option to copy the libraries to the Arduino Core folder is enabled, it will already be available for use in the Arduino IDE. Otherwise, you can find the compiled libraries in the `esp32-arduino-libs` folder alongside this repository.
39+
- Note that the copy operation doesn't currently support the core downloaded from the Arduino IDE Boards Manager, only the manual installation from the [`arduino-esp32`](https://github.com/espressif/arduino-esp32) repository.
40+
1541
### Documentation
1642

1743
For more information about how to use the Library builder, please refer to this [Documentation page](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html?highlight=lib%20builder)

Diff for: tools/config_editor/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.venv/
2+
__pycache__/

Diff for: tools/config_editor/README.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Arduino Static Libraries Configuration Editor
2+
3+
This is a simple application to configure the static libraries for the ESP32 Arduino core.
4+
It allows the user to select the targets to compile, change the configuration options and compile the libraries.
5+
It has mouse support and can be pre-configured using command line arguments.
6+
7+
## Requirements
8+
- Python 3.9 or later
9+
- The "textual" library (install it using `pip install textual`)
10+
- The requirements from esp32-arduino-lib-builder
11+
12+
## Troubleshooting
13+
14+
In some cases, the UI might not look as expected. This can happen due to the terminal emulator not supporting the required features.
15+
16+
### WSL
17+
18+
If you are using WSL, it is recommended to use the Windows Terminal to visualize the application. Otherwise, the application layout and colors might not be displayed correctly.
19+
The Windows Terminal can be installed from the Microsoft Store.
20+
21+
### MacOS
22+
23+
If you are using MacOS and the application looks weird, check [this guide from Textual](https://textual.textualize.io/FAQ/#why-doesnt-textual-look-good-on-macos) to fix it.
24+
25+
## Usage
26+
27+
These command line arguments can be used to pre-configure the application:
28+
29+
Command line arguments:
30+
-t, --target <target> Comma-separated list of targets to be compiled.
31+
Choose from: all, esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2. Default: all except esp32c2
32+
--copy, --no-copy Enable/disable copying the compiled libraries to arduino-esp32. Enabled by default
33+
-c, --arduino-path <path> Path to arduino-esp32 directory. Default: OS dependent
34+
-A, --arduino-branch <branch> Branch of the arduino-esp32 repository to be used. Default: set by the build script
35+
-I, --idf-branch <branch> Branch of the ESP-IDF repository to be used. Default: set by the build script
36+
-i, --idf-commit <commit> Commit of the ESP-IDF repository to be used. Default: set by the build script
37+
-D, --debug-level <level> Debug level to be set to ESP-IDF.
38+
Choose from: default, none, error, warning, info, debug, verbose. Default: default

Diff for: tools/config_editor/app.py

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Arduino Static Libraries Configuration Editor
5+
6+
This is a simple application to configure the static libraries for the ESP32 Arduino core.
7+
It allows the user to select the targets to compile, change the configuration options and compile the libraries.
8+
9+
Requires Python 3.9 or later.
10+
11+
The application is built using the "textual" library, which is a Python library for building text-based user interfaces.
12+
13+
Note that this application still needs the requirements from esp32-arduino-lib-builder to be installed.
14+
15+
Command line arguments:
16+
-t, --target <target> Comma-separated list of targets to be compiled.
17+
Choose from: all, esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2. Default: all except esp32c2
18+
--copy, --no-copy Enable/disable copying the compiled libraries to arduino-esp32. Enabled by default
19+
-c, --arduino-path <path> Path to arduino-esp32 directory. Default: OS dependent
20+
-A, --arduino-branch <branch> Branch of the arduino-esp32 repository to be used. Default: set by the build script
21+
-I, --idf-branch <branch> Branch of the ESP-IDF repository to be used. Default: set by the build script
22+
-i, --idf-commit <commit> Commit of the ESP-IDF repository to be used. Default: set by the build script
23+
-D, --debug-level <level> Debug level to be set to ESP-IDF.
24+
Choose from: default, none, error, warning, info, debug, verbose. Default: default
25+
26+
"""
27+
28+
import argparse
29+
import json
30+
import os
31+
import platform
32+
import sys
33+
34+
from pathlib import Path
35+
36+
try:
37+
from textual.app import App, ComposeResult
38+
from textual.binding import Binding
39+
from textual.containers import VerticalScroll
40+
from textual.screen import Screen
41+
from textual.widgets import Button, Header, Label, Footer
42+
except ImportError:
43+
print("Please install the \"textual\" package before running this script.")
44+
exit(1)
45+
46+
from settings import SettingsScreen
47+
from editor import EditorScreen
48+
from compile import CompileScreen
49+
50+
class MainScreen(Screen):
51+
# Main screen class
52+
53+
# Set the key bindings
54+
BINDINGS = [
55+
Binding("c", "app.push_screen('compile')", "Compile"),
56+
Binding("e", "app.push_screen('editor')", "Editor"),
57+
Binding("s", "app.push_screen('settings')", "Settings"),
58+
Binding("q", "app.quit", "Quit"),
59+
]
60+
61+
def on_button_pressed(self, event: Button.Pressed) -> None:
62+
# Event handler called when a button is pressed
63+
if event.button.id == "compile-button":
64+
print("Compile button pressed")
65+
self.app.push_screen("compile")
66+
elif event.button.id == "settings-button":
67+
print("Settings button pressed")
68+
self.app.push_screen("settings")
69+
elif event.button.id == "editor-button":
70+
print("Editor button pressed")
71+
self.app.push_screen("editor")
72+
elif event.button.id == "quit-button":
73+
print("Quit button pressed")
74+
self.app.exit()
75+
76+
def compose(self) -> ComposeResult:
77+
# Compose main menu
78+
yield Header()
79+
with VerticalScroll(id="main-menu-container"):
80+
yield Label("ESP32 Arduino Static Libraries Configuration Editor", id="main-menu-title")
81+
yield Button("Compile Static Libraries", id="compile-button", classes="main-menu-button")
82+
yield Button("Sdkconfig Editor", id="editor-button", classes="main-menu-button")
83+
yield Button("Settings", id="settings-button", classes="main-menu-button")
84+
yield Button("Quit", id="quit-button", classes="main-menu-button")
85+
yield Footer()
86+
87+
def on_mount(self) -> None:
88+
# Event handler called when the app is mounted for the first time
89+
self.title = "Configurator"
90+
self.sub_title = "Main Menu"
91+
print("Main screen mounted.")
92+
93+
class ConfigEditorApp(App):
94+
# Main application class
95+
96+
# Set the root and script paths
97+
SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
98+
ROOT_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, "..", ".."))
99+
100+
# Set the application options
101+
supported_targets = []
102+
setting_enable_copy = True
103+
104+
# Options to be set by the command line arguments
105+
setting_target = ""
106+
setting_arduino_path = ""
107+
setting_arduino_branch = ""
108+
setting_idf_branch = ""
109+
setting_idf_commit = ""
110+
setting_debug_level = ""
111+
112+
ENABLE_COMMAND_PALETTE = False
113+
CSS_PATH = "style.tcss"
114+
SCREENS = {
115+
"main": MainScreen(),
116+
"settings": SettingsScreen(),
117+
"compile": CompileScreen(),
118+
"editor": EditorScreen(),
119+
}
120+
121+
def on_mount(self) -> None:
122+
print("Application mounted. Initial options:")
123+
print("Python version: " + sys.version)
124+
print("Root path: " + self.ROOT_PATH)
125+
print("Script path: " + self.SCRIPT_PATH)
126+
print("Supported Targets: " + ", ".join(self.supported_targets))
127+
print("Default targets: " + self.setting_target)
128+
print("Enable Copy: " + str(self.setting_enable_copy))
129+
print("Arduino Path: " + str(self.setting_arduino_path))
130+
print("Arduino Branch: " + str(self.setting_arduino_branch))
131+
print("IDF Branch: " + str(self.setting_idf_branch))
132+
print("IDF Commit: " + str(self.setting_idf_commit))
133+
print("IDF Debug Level: " + str(self.setting_debug_level))
134+
self.push_screen("main")
135+
136+
def arduino_default_path():
137+
sys_name = platform.system()
138+
home = str(Path.home())
139+
if sys_name == "Linux":
140+
return os.path.join(home, "Arduino", "hardware", "espressif", "esp32")
141+
else: # Windows and MacOS
142+
return os.path.join(home, "Documents", "Arduino", "hardware", "espressif", "esp32")
143+
144+
def check_arduino_path(path):
145+
return os.path.isdir(path)
146+
147+
def main() -> None:
148+
# Set the PYTHONUNBUFFERED environment variable to "1" to disable the output buffering
149+
os.environ['PYTHONUNBUFFERED'] = "1"
150+
151+
# Check Python version
152+
if sys.version_info < (3, 9):
153+
print("This script requires Python 3.9 or later")
154+
exit(1)
155+
156+
app = ConfigEditorApp()
157+
158+
# List of tuples for the target choices containing the target name and if it is enabled by default
159+
target_choices = []
160+
161+
# Parse build JSON file
162+
build_json_path = os.path.join(app.ROOT_PATH, "configs", "builds.json")
163+
if os.path.isfile(build_json_path):
164+
with open(build_json_path, "r") as build_json_file:
165+
build_json = json.load(build_json_file)
166+
for target in build_json["targets"]:
167+
try:
168+
default = False if target["skip"] else True
169+
except:
170+
default = True
171+
target_choices.append((target["target"], default))
172+
else:
173+
print("Error: configs/builds.json file not found.")
174+
exit(1)
175+
176+
target_choices.sort(key=lambda x: x[0])
177+
178+
parser = argparse.ArgumentParser(description="Configure and compile the ESP32 Arduino static libraries")
179+
180+
parser.add_argument("-t", "--target",
181+
metavar="<target>",
182+
type=str,
183+
default="default",
184+
required=False,
185+
help="Comma-separated list of targets to be compiled. Choose from: " + ", ".join([x[0] for x in target_choices])
186+
+ ". Default: All except " + ", ".join([x[0] for x in target_choices if not x[1]]))
187+
188+
parser.add_argument("--copy",
189+
type=bool,
190+
action=argparse.BooleanOptionalAction,
191+
default=True,
192+
required=False,
193+
help="Enable/disable copying the compiled libraries to arduino-esp32. Enabled by default")
194+
195+
parser.add_argument("-c", "--arduino-path",
196+
metavar="<arduino path>",
197+
type=str,
198+
default=arduino_default_path(),
199+
required=False,
200+
help="Path to arduino-esp32 directory. Default: " + arduino_default_path())
201+
202+
parser.add_argument("-A", "--arduino-branch",
203+
metavar="<arduino branch>",
204+
type=str,
205+
default="",
206+
required=False,
207+
help="Branch of the arduino-esp32 repository to be used")
208+
209+
parser.add_argument("-I", "--idf-branch",
210+
metavar="<IDF branch>",
211+
type=str,
212+
default="",
213+
required=False,
214+
help="Branch of the ESP-IDF repository to be used")
215+
216+
parser.add_argument("-i", "--idf-commit",
217+
metavar="<IDF commit>",
218+
type=str,
219+
default="",
220+
required=False,
221+
help="Commit of the ESP-IDF repository to be used")
222+
223+
debug_level_choices = ("default", "none", "error", "warning", "info", "debug", "verbose")
224+
parser.add_argument("-D", "--debug-level",
225+
metavar="<level>",
226+
type=str,
227+
default="default",
228+
choices=debug_level_choices,
229+
required=False,
230+
help="Debug level to be set to ESP-IDF. Choose from: " + ", ".join(debug_level_choices))
231+
232+
args = parser.parse_args()
233+
234+
# Set the options in the app
235+
if args.target.strip() == "default":
236+
args.target = ",".join([x[0] for x in target_choices if x[1]])
237+
elif args.target.strip() == "all":
238+
args.target = ",".join([x[0] for x in target_choices])
239+
240+
app.supported_targets = [x[0] for x in target_choices]
241+
242+
for target in args.target.split(","):
243+
if target not in app.supported_targets:
244+
print("Invalid target: " + target)
245+
exit(1)
246+
247+
app.setting_target = args.target
248+
249+
if args.copy:
250+
if check_arduino_path(args.arduino_path):
251+
app.setting_enable_copy = True
252+
elif args.arduino_path == arduino_default_path():
253+
print("Warning: Default Arduino path not found. Disabling copy to Arduino.")
254+
app.setting_enable_copy = False
255+
else:
256+
print("Invalid path to Arduino core: " + os.path.abspath(args.arduino_path))
257+
exit(1)
258+
else:
259+
app.setting_enable_copy = False
260+
261+
app.setting_arduino_path = os.path.abspath(args.arduino_path)
262+
app.setting_arduino_branch = args.arduino_branch
263+
app.setting_idf_branch = args.idf_branch
264+
app.setting_idf_commit = args.idf_commit
265+
app.setting_debug_level = args.debug_level
266+
267+
# Change to the root directory of the app to the root of the project
268+
os.chdir(app.ROOT_PATH)
269+
270+
# Main function to run the app
271+
app.run()
272+
273+
# Propagate the exit code from the app
274+
exit(app.return_code or 0)
275+
276+
if __name__ == "__main__":
277+
# If this script is run directly, start the app
278+
main()

0 commit comments

Comments
 (0)