fastled 1.0.15__py2.py3-none-any.whl → 1.0.17__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: fastled
3
+ Version: 1.0.17
4
+ Summary: FastLED Wasm Compiler
5
+ Home-page: https://github.com/zackees/fastled-wasm
6
+ Maintainer: Zachary Vorhies
7
+ License: BSD 3-Clause License
8
+ Keywords: template-python-cmd
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: docker
14
+ Requires-Dist: httpx
15
+ Requires-Dist: watchdog
16
+ Requires-Dist: livereload
17
+ Requires-Dist: download
18
+ Requires-Dist: filelock
19
+
20
+ # FastLED wasm compiler
21
+
22
+ Compiles an Arduino/Platformio sketch into a wasm binary that can be run directly in the web browser.
23
+
24
+ [![Linting](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/lint.yml)
25
+ [![Build and Push Multi Docker Image](https://github.com/zackees/fastled-wasm/actions/workflows/build_multi_docker_image.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/build_multi_docker_image.yml)
26
+ [![MacOS_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_macos.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_macos.yml)
27
+ [![Ubuntu_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_ubuntu.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_ubuntu.yml)
28
+ [![Win_Tests](https://github.com/zackees/fastled-wasm/actions/workflows/test_win.yml/badge.svg)](https://github.com/zackees/fastled-wasm/actions/workflows/test_win.yml)
29
+
30
+
31
+
32
+ # About
33
+
34
+ This python app will compile your FastLED style sketches into html/js/wasm output that runs directly in the browser.
35
+
36
+ Compile times are extremely fast - I've seen as low as 5 seconds but 8-15 seconds is typical.
37
+
38
+ This works on Windows/Linux/Mac(arm/x64).
39
+
40
+ Docker is required.
41
+
42
+ https://github.com/user-attachments/assets/64ae0e6c-5f8b-4830-ab87-dcc25bc61218
43
+
44
+ # Demo
45
+
46
+ https://zackees.github.io/fastled-wasm/
47
+
48
+
49
+
50
+ # Install
51
+
52
+ ```bash
53
+ pip install fastled-wasm
54
+ ```
55
+
56
+ **Note that you may need to install x86 docker emulation on Mac-m1 and later, as this is an x86 only image at the prsent.**
57
+
58
+ # Use
59
+
60
+ Change to the directory where the sketch lives and run
61
+
62
+ ```bash
63
+ cd <SKETCH-DIRECTORY>
64
+ fastled-wasm
65
+ ```
66
+
67
+ Or if you don't have docker then use our web compiler
68
+
69
+ ```bash
70
+ cd <SKETCH-DIRECTORY>
71
+ fastled-wasm --web
72
+ ```
73
+
74
+ After compilation a web browser windows will pop up.
75
+
76
+ # Hot reload by default
77
+
78
+ Once launched, the compiler will remain open, listening to changes and recompiling as necessary and hot-reloading the sketch into the current browser.
79
+
80
+ This style of development should be familiar to those doing web development.
81
+
82
+ # Data
83
+
84
+ If you want to embed data, then do so in the `data/` directory at the project root. The files will appear in the `data/` director of any spawned FileSystem or SDCard.
85
+
86
+
87
+ ### About the compilation.
88
+
89
+ Pre-processing is done to your source files. A fake Arduino.h will be inserted into your source files that will
90
+ provide shims for most of the common api points.
91
+
92
+
93
+ # Revisions
94
+
95
+ * 1.0.17 - Pulls updates when necessary. Removed dependency on keyring.
96
+ * 1.0.16 - `fastled-wasm` package name has been changed to `fled`
97
+ * 1.0.15 - `fled` is an alias of `fastled-wasm` and will eventually replace it. `--web-host` was folded into `--web`, which if unspecified will attempt to run a local docker server and fallback to the cloud server if that fails. Specifying `--web` with no arguments will default to the cloud server while an argument (like `localhost`) will cause it to bind to that already running server for compilation.
98
+ * 1.0.14 - For non significant changes (comments, whitespace) in C++/ino/*.h files, compilation is skipped. This significantly reduces load on the server and prevents unnecessary local client browser refreshes.
99
+ * 1.0.13 - Increase speed of local compiles by running the server version of the compiler so it can keep it's cache and not have to pay docker startup costs because now it's a persistant server until exit.
100
+ * 1.0.12 - Added suppport for compile modes. Pass in `--release`, `--quick`, `--debug` for different compile options. We also support `--profile` to profile the build process.
101
+ * 1.0.11 - `--web` compile will automatically be enabled if the local build using docker fails.
102
+ * 1.0.10 - Watching files is now available for `--web`
103
+ * 1.0.9 - Enabled web compile. Access it with `--web` or `--web-host`
104
+ * 1.0.8 - Allow more than one fastled-wasm browser instances to co-exist by searching for unused ports after 8081.
105
+ * 1.0.7 - Docker multi image build implemented, tool now points to new docker image compile.
106
+ * 1.0.6 - Removed `--no-open` and `--watch`, `--watch` is now assumed unless `--just-compile` is used.
107
+ * 1.0.5 - Implemented `--update` to update the compiler image from the docker registry.
108
+ * 1.0.4 - Implemented `--watch` which will watch for changes and then re-launch the compilation step.
109
+ * 1.0.3 - Integrated `live-server` to launch when available.
110
+ * 1.0.2 - Small bug with new installs.
111
+ * 1.0.1 - Re-use is no longer the default, due to problems.
112
+ * 1.0.0 - Initial release.
@@ -0,0 +1,18 @@
1
+ fled/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ fled/app.py,sha256=EwP7CrMT7cEmc4A-rIEN7uEC77k6NFPATT2zkyMSKcY,11362
3
+ fled/build_mode.py,sha256=joMwsV4K1y_LijT4gEAcjx69RZBoe_KmFmHZdPYbL_4,631
4
+ fled/check_cpp_syntax.py,sha256=YxRJm7cFPv4bdhL1v_KOkBz8RL86ihayoJYvclr69ms,1024
5
+ fled/cli.py,sha256=g2oXoJAmpUYEgXCLVzu0fekJjgWhuLCpXmCkl8kvCQI,234
6
+ fled/compile_server.py,sha256=Hj2Hem4M4cD2NkdRwZj5q4Y6vdonnpaRk2pAWSwnsC8,7991
7
+ fled/docker_manager.py,sha256=eEc12bmQEER7xf-7ehfYJgQua9cDB1IlLVuuw_9eflI,8934
8
+ fled/filewatcher.py,sha256=SHKx9Dnt4EJiT-iPYakdPZBRIL1gsJGN9tY8FJW2myU,5079
9
+ fled/open_browser.py,sha256=-VhpGmydwLCcXmrDD2esMEdJPZYcoX2Mt73eb88Nna0,1392
10
+ fled/paths.py,sha256=VsPmgu0lNSCFOoEC0BsTYzDygXqy15AHUfN-tTuzDZA,99
11
+ fled/web_compile.py,sha256=9_TJ_R8Iv6WTbLvZ_nVNrpfWPWBanhXbi8l_O-ADyCM,6369
12
+ fled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
13
+ fastled-1.0.17.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
14
+ fastled-1.0.17.dist-info/METADATA,sha256=-J_L3EyUBKaEezj59c8kN7XdfGbTiApo0WA1urjHnSE,5230
15
+ fastled-1.0.17.dist-info/WHEEL,sha256=0VNUDWQJzfRahYI3neAhz2UVbRCtztpN5dPHAGvmGXc,109
16
+ fastled-1.0.17.dist-info/entry_points.txt,sha256=aw_M3Wl5jLJEJm0wlVD3Hr0cDqILc9frPbKeJfdNqyM,68
17
+ fastled-1.0.17.dist-info/top_level.txt,sha256=QuCwo_EQ7IOcAlszLUCg8n-oQZey7zyCyH3yShSLwcQ,11
18
+ fastled-1.0.17.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ fastled-wasm = fled.cli:main
3
+ fled = fled.cli:main
@@ -0,0 +1,2 @@
1
+ cache
2
+ fled
fled/__init__.py ADDED
File without changes
{fastled → fled}/app.py RENAMED
@@ -1,5 +1,7 @@
1
1
  """
2
2
  Uses the latest wasm compiler image to compile the FastLED sketch.
3
+
4
+
3
5
  """
4
6
 
5
7
  import argparse
@@ -13,15 +15,12 @@ import time
13
15
  from dataclasses import dataclass
14
16
  from pathlib import Path
15
17
 
16
- from fastled import __version__
17
- from fastled.build_mode import BuildMode, get_build_mode
18
- from fastled.compile_server import CompileServer
19
- from fastled.docker_manager import DockerManager
20
- from fastled.filewatcher import FileWatcherProcess
21
- from fastled.keyboard import SpaceBarWatcher
22
- from fastled.open_browser import open_browser_thread
23
- from fastled.sketch import looks_like_fastled_repo, looks_like_sketch_directory
24
- from fastled.web_compile import ConnectionResult, find_good_connection, web_compile
18
+ from fled.build_mode import BuildMode, get_build_mode
19
+ from fled.compile_server import CompileServer
20
+ from fled.docker_manager import DockerManager
21
+ from fled.filewatcher import FileChangedNotifier
22
+ from fled.open_browser import open_browser_thread
23
+ from fled.web_compile import web_compile
25
24
 
26
25
  machine = platform.machine().lower()
27
26
  IS_ARM: bool = "arm" in machine or "aarch64" in machine
@@ -44,15 +43,12 @@ DOCKER = DockerManager(container_name=CONTAINER_NAME)
44
43
 
45
44
  def parse_args() -> argparse.Namespace:
46
45
  """Parse command-line arguments."""
47
- parser = argparse.ArgumentParser(description=f"FastLED WASM Compiler {__version__}")
48
- parser.add_argument(
49
- "--version", action="version", version=f"%(prog)s {__version__}"
50
- )
46
+ parser = argparse.ArgumentParser(description="FastLED WASM Compiler")
51
47
  parser.add_argument(
52
48
  "directory",
53
49
  type=str,
54
50
  nargs="?",
55
- default=None,
51
+ default=os.getcwd(),
56
52
  help="Directory containing the FastLED sketch to compile",
57
53
  )
58
54
  parser.add_argument(
@@ -60,6 +56,11 @@ def parse_args() -> argparse.Namespace:
60
56
  action="store_true",
61
57
  help="Just compile, skip opening the browser and watching for changes.",
62
58
  )
59
+ parser.add_argument(
60
+ "--no-auto-clean",
61
+ action="store_true",
62
+ help="Big performance gains for compilation, but it's flaky at this time",
63
+ )
63
64
  parser.add_argument(
64
65
  "--web",
65
66
  "-w",
@@ -70,10 +71,15 @@ def parse_args() -> argparse.Namespace:
70
71
  help="Use web compiler. Optional URL can be provided (default: https://fastled.onrender.com)",
71
72
  )
72
73
  parser.add_argument(
73
- "-i",
74
- "--interactive",
74
+ "--reuse",
75
75
  action="store_true",
76
- help="Run in interactive mode (Not available with --web)",
76
+ help="Reuse the existing container if it exists. (Not available with --web)",
77
+ )
78
+ parser.add_argument(
79
+ "--exclude",
80
+ type=str,
81
+ nargs="+",
82
+ help="Additional patterns to exclude from file watching (Not available with --web)",
77
83
  )
78
84
  parser.add_argument(
79
85
  "--profile",
@@ -91,17 +97,6 @@ def parse_args() -> argparse.Namespace:
91
97
  build_mode.add_argument(
92
98
  "--release", action="store_true", help="Build in release mode"
93
99
  )
94
- build_mode.add_argument(
95
- "--localhost",
96
- "--local",
97
- action="store_true",
98
- help="Use localhost for web compilation from an instance of fastled --server, creating it if necessary",
99
- )
100
- build_mode.add_argument(
101
- "--server",
102
- action="store_true",
103
- help="Run the server in the current directory, volume mapping fastled if we are in the repo",
104
- )
105
100
 
106
101
  build_mode.add_argument(
107
102
  "--force-compile",
@@ -109,30 +104,14 @@ def parse_args() -> argparse.Namespace:
109
104
  help="Skips the test to see if the current directory is a valid FastLED sketch directory",
110
105
  )
111
106
 
112
- cwd_is_fastled = looks_like_fastled_repo(Path(os.getcwd()))
113
-
114
107
  args = parser.parse_args()
115
- if not cwd_is_fastled and not args.localhost and not args.web and not args.server:
116
- print(f"Using web compiler at {DEFAULT_URL}")
117
- args.web = DEFAULT_URL
118
- if cwd_is_fastled and not args.web:
119
- print("Forcing --local mode because we are in the FastLED repo")
120
- args.localhost = True
121
- if args.localhost:
122
- args.web = "localhost"
123
- if args.interactive and not args.server:
124
- print("--interactive forces --server mode")
125
- args.server = True
126
- if args.directory is None and not args.server:
127
- # does current directory look like a sketch?
128
- maybe_sketch_dir = Path(os.getcwd())
129
- if looks_like_sketch_directory(maybe_sketch_dir):
130
- args.directory = str(maybe_sketch_dir)
131
- else:
132
- print(
133
- "\nYou either need to specify a sketch directory or run in --server mode."
134
- )
135
- sys.exit(1)
108
+
109
+ # Handle --web implications
110
+ if args.web:
111
+ if args.reuse:
112
+ parser.error("--reuse cannot be used with --web")
113
+ if args.exclude:
114
+ parser.error("--exclude cannot be used with --web")
136
115
 
137
116
  return args
138
117
 
@@ -169,7 +148,9 @@ def run_web_compiler(
169
148
 
170
149
  # now check to see if the hash value is the same as the last hash value
171
150
  if last_hash_value is not None and last_hash_value == web_result.hash_value:
172
- print("\nSkipping redeploy: No significant changes found.")
151
+ print(
152
+ "\nNo significant source code changes detected and data was the same, skipping recompilation."
153
+ )
173
154
  print_results()
174
155
  return CompiledResult(
175
156
  success=True, fastled_js=str(output_dir), hash_value=web_result.hash_value
@@ -197,29 +178,16 @@ def run_web_compiler(
197
178
 
198
179
 
199
180
  def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServer:
200
- is_local_host = "localhost" in args.web or "127.0.0.1" in args.web or args.localhost
201
-
202
- # test to see if there is already a local host server
203
- local_host_needs_server = False
204
- if is_local_host:
205
- addr = "localhost" if args.localhost else args.web
206
- result: ConnectionResult | None = find_good_connection([addr])
207
- if result is not None:
208
- print(f"Found local server at {result.host}")
209
- return result.host
210
- else:
211
- local_host_needs_server = True
212
-
213
- if not local_host_needs_server and args.web:
181
+ if args.web:
214
182
  if isinstance(args.web, str):
215
183
  return args.web
216
184
  if isinstance(args.web, bool):
217
185
  return DEFAULT_URL
218
186
  return args.web
219
187
  else:
188
+ disable_auto_clean = args.no_auto_clean
220
189
  try:
221
- print("No local server found, starting one...")
222
- compile_server = CompileServer()
190
+ compile_server = CompileServer(disable_auto_clean=disable_auto_clean)
223
191
  print("Waiting for the local compiler to start...")
224
192
  if not compile_server.wait_for_startup():
225
193
  print("Failed to start local compiler.")
@@ -232,11 +200,31 @@ def _try_start_server_or_get_url(args: argparse.Namespace) -> str | CompileServe
232
200
  return DEFAULT_URL
233
201
 
234
202
 
235
- def run_client(args: argparse.Namespace) -> int:
236
- compile_server: CompileServer | None = None
237
- open_web_browser = not args.just_compile and not args.interactive
203
+ def _looks_like_sketch_directory(directory: Path) -> bool:
204
+ # walk the path and if there are over 30 files, return False
205
+ # at the root of the directory there should either be an ino file or a src directory
206
+ # or some cpp files
207
+ # if there is a platformio.ini file, return True
208
+ ino_file_at_root = list(directory.glob("*.ino"))
209
+ if ino_file_at_root:
210
+ return True
211
+ cpp_file_at_root = list(directory.glob("*.cpp"))
212
+ if cpp_file_at_root:
213
+ return True
214
+ platformini_file = list(directory.glob("platformio.ini"))
215
+ if platformini_file:
216
+ return True
217
+ return False
218
+
219
+
220
+ def main() -> int:
221
+ args = parse_args()
222
+ open_web_browser = not args.just_compile
238
223
  profile = args.profile
239
- if not args.force_compile and not looks_like_sketch_directory(Path(args.directory)):
224
+
225
+ if not args.force_compile and not _looks_like_sketch_directory(
226
+ Path(args.directory)
227
+ ):
240
228
  print(
241
229
  "Error: Not a valid FastLED sketch directory, if you are sure it is, use --force-compile"
242
230
  )
@@ -249,16 +237,16 @@ def run_client(args: argparse.Namespace) -> int:
249
237
  )
250
238
  args.web = True
251
239
 
240
+ compile_server: CompileServer | None = None
252
241
  url: str
242
+
253
243
  try:
254
244
  try:
255
245
  url_or_server: str | CompileServer = _try_start_server_or_get_url(args)
256
246
  if isinstance(url_or_server, str):
257
- print(f"Found URL: {url_or_server}")
258
247
  url = url_or_server
259
248
  else:
260
249
  compile_server = url_or_server
261
- print(f"Server started at {compile_server.url()}")
262
250
  url = compile_server.url()
263
251
  except KeyboardInterrupt:
264
252
  print("\nExiting from first try...")
@@ -315,115 +303,49 @@ def run_client(args: argparse.Namespace) -> int:
315
303
  compile_server.stop()
316
304
  return 1
317
305
 
306
+ # Watch mode
318
307
  print("\nWatching for changes. Press Ctrl+C to stop...")
319
- sketch_filewatcher = FileWatcherProcess(
320
- args.directory, excluded_patterns=["fastled_js"]
321
- )
322
-
323
- source_code_watcher: FileWatcherProcess | None = None
324
- if compile_server and compile_server.using_fastled_src_dir_volume():
325
- assert compile_server.fastled_src_dir is not None
326
- source_code_watcher = FileWatcherProcess(
327
- compile_server.fastled_src_dir, excluded_patterns=[]
328
- )
329
-
330
- def trigger_rebuild_if_sketch_changed(
331
- last_compiled_result: CompiledResult,
332
- ) -> CompiledResult:
333
- changed_files = sketch_filewatcher.get_all_changes()
334
- if changed_files:
335
- print(f"\nChanges detected in {changed_files}")
336
- last_hash_value = last_compiled_result.hash_value
337
- out = compile_function(last_hash_value=last_hash_value)
338
- if not out.success:
339
- print("\nRecompilation failed.")
340
- else:
341
- print("\nRecompilation successful.")
342
- return out
343
- return last_compiled_result
308
+ watcher = FileChangedNotifier(args.directory, excluded_patterns=["fastled_js"])
309
+ watcher.start()
344
310
 
345
311
  try:
346
312
  while True:
347
- last_compiled_result = trigger_rebuild_if_sketch_changed(
348
- last_compiled_result
349
- )
350
- if compile_server and not compile_server.proceess_running():
351
- print("Server process is not running. Exiting...")
352
- return 1
353
- if source_code_watcher is not None:
354
- changed_files = source_code_watcher.get_all_changes()
355
- if changed_files:
356
- print(f"\nChanges detected in FastLED source code: {changed_files}")
357
- print("Press space bar to trigger compile.")
358
-
359
- space_key_watcher = SpaceBarWatcher()
360
- try:
361
- while True:
362
- if space_key_watcher.space_bar_pressed():
363
- print("Space bar pressed, triggering recompile...")
364
- last_compiled_result = compile_function(
365
- last_hash_value=None
366
- )
367
- print("Finished recompile.")
368
- break
369
- elif len(sketch_filewatcher.get_all_changes()) > 0:
370
- last_compiled_result = compile_function(
371
- last_hash_value=None
372
- )
373
- break
374
- time.sleep(0.1)
375
- finally:
376
- space_key_watcher.stop()
377
-
313
+ try:
314
+ changed_files = watcher.get_all_changes()
315
+ except KeyboardInterrupt:
316
+ print("\nExiting from watcher...")
317
+ raise
318
+ except Exception as e:
319
+ print(f"Error getting changes: {e}")
320
+ changed_files = []
321
+ if changed_files:
322
+ print(f"\nChanges detected in {changed_files}")
323
+ last_hash_value = last_compiled_result.hash_value
324
+ result = compile_function(last_hash_value=last_hash_value)
325
+ if not result.success:
326
+ print("\nRecompilation failed.")
327
+ else:
328
+ print("\nRecompilation successful.")
329
+ time.sleep(0.3)
378
330
  except KeyboardInterrupt:
331
+ watcher.stop()
379
332
  print("\nStopping watch mode...")
380
333
  return 0
381
334
  except Exception as e:
335
+ watcher.stop()
382
336
  print(f"Error: {e}")
383
337
  return 1
384
338
  finally:
385
- sketch_filewatcher.stop()
339
+ watcher.stop()
386
340
  if compile_server:
387
341
  compile_server.stop()
388
342
  if browser_proc:
389
343
  browser_proc.kill()
390
344
 
391
345
 
392
- def run_server(args: argparse.Namespace) -> int:
393
- interactive = args.interactive
394
- compile_server = CompileServer(interactive=interactive)
395
- if not interactive:
396
- print(f"Server started at {compile_server.url()}")
397
- compile_server.wait_for_startup()
398
- try:
399
- while True:
400
- if not compile_server.proceess_running():
401
- print("Server process is not running. Exiting...")
402
- return 1
403
- time.sleep(1)
404
- except KeyboardInterrupt:
405
- print("\nExiting from server...")
406
- return 1
407
- finally:
408
- compile_server.stop()
409
- return 0
410
-
411
-
412
- def main() -> int:
413
- args = parse_args()
414
- if args.server:
415
- print("Running in server only mode.")
416
- return run_server(args)
417
- else:
418
- print("Running in client/server mode.")
419
- return run_client(args)
420
-
421
-
422
346
  if __name__ == "__main__":
423
347
  try:
424
- # os.chdir("../fastled")
425
- sys.argv.append("examples/SdCard")
426
- sys.argv.append("--localhost")
348
+ sys.argv.append("examples/wasm")
427
349
  sys.exit(main())
428
350
  except KeyboardInterrupt:
429
351
  print("\nExiting from main...")
@@ -0,0 +1,34 @@
1
+ from pygments import lex
2
+ from pygments.lexers import CppLexer
3
+ from pygments.token import Token
4
+
5
+
6
+ def check_cpp_syntax(code):
7
+ try:
8
+ # Tokenize the code to check for basic syntax issues
9
+ for token_type, token_value in lex(code, CppLexer()):
10
+ if token_type == Token.Error:
11
+ print(f"Syntax error detected: {token_value}")
12
+ return False
13
+ print("No syntax errors detected.")
14
+ return True
15
+ except Exception as e:
16
+ print(f"Error during syntax check: {e}")
17
+ return False
18
+
19
+
20
+ def main():
21
+ file_path = input("Enter the path to your C++ file: ")
22
+ try:
23
+ with open(file_path, "r") as file:
24
+ code = file.read()
25
+ if check_cpp_syntax(code):
26
+ print("The file can now be sent to the server.")
27
+ else:
28
+ print("Please fix the syntax errors before sending.")
29
+ except FileNotFoundError:
30
+ print("File not found. Please check the path and try again.")
31
+
32
+
33
+ if __name__ == "__main__":
34
+ main()
{fastled → fled}/cli.py RENAMED
@@ -4,7 +4,7 @@ Main entry point.
4
4
 
5
5
  import sys
6
6
 
7
- from fastled.app import main as app_main
7
+ from fled.app import main as app_main
8
8
 
9
9
 
10
10
  def main() -> int: