├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── images
├── beats.png
├── color.png
├── get_led.png
├── get_led_selectors.png
├── get_sections.png
├── headerimage.jpg
├── light_up.png
├── moving_dot.png
├── off.png
├── on.png
├── patreon_button.svg
├── rainbow.png
├── test_animations.png
├── transition.png
└── write.png
├── neopixel_plus
├── __init__.py
├── animations
│ ├── __init__.py
│ ├── beats_up_and_down.py
│ ├── light_up.py
│ ├── moving_dot.py
│ ├── rainbow.py
│ └── transition.py
├── helper
│ ├── __init__.py
│ └── colors.py
└── neopixel_plus.py
└── setup.py
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: glowingkitty # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: marcoEDU # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 | pyvenv/
9 | .vscode
10 |
11 | # Distribution / packaging
12 | .Python
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | pip-wheel-metadata/
26 | share/python-wheels/
27 | *.egg-info/
28 | .installed.cfg
29 | *.egg
30 | MANIFEST
31 |
32 | # PyInstaller
33 | # Usually these files are written by a python script from a template
34 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
35 | *.manifest
36 | *.spec
37 |
38 | # Installer logs
39 | pip-log.txt
40 | pip-delete-this-directory.txt
41 |
42 | # Unit test / coverage reports
43 | htmlcov/
44 | .tox/
45 | .nox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *.cover
52 | *.py,cover
53 | .hypothesis/
54 | .pytest_cache/
55 |
56 | # Translations
57 | *.mo
58 | *.pot
59 |
60 | # Django stuff:
61 | *.log
62 | local_settings.py
63 | db.sqlite3
64 | db.sqlite3-journal
65 |
66 | # Flask stuff:
67 | instance/
68 | .webassets-cache
69 |
70 | # Scrapy stuff:
71 | .scrapy
72 |
73 | # Sphinx documentation
74 | docs/_build/
75 |
76 | # PyBuilder
77 | target/
78 |
79 | # Jupyter Notebook
80 | .ipynb_checkpoints
81 |
82 | # IPython
83 | profile_default/
84 | ipython_config.py
85 |
86 | # pyenv
87 | .python-version
88 |
89 | # pipenv
90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
93 | # install all needed dependencies.
94 | #Pipfile.lock
95 |
96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
97 | __pypackages__/
98 |
99 | # Celery stuff
100 | celerybeat-schedule
101 | celerybeat.pid
102 |
103 | # SageMath parsed files
104 | *.sage.py
105 |
106 | # Environments
107 | .env
108 | .venv
109 | env/
110 | venv/
111 | ENV/
112 | env.bak/
113 | venv.bak/
114 |
115 | # Spyder project settings
116 | .spyderproject
117 | .spyproject
118 |
119 | # Rope project settings
120 | .ropeproject
121 |
122 | # mkdocs documentation
123 | /site
124 |
125 | # mypy
126 | .mypy_cache/
127 | .dmypy.json
128 | dmypy.json
129 |
130 | # Pyre type checker
131 | .pyre/
132 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Marco
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | The NeoPixel library plus animations and terminal testing mode - so you can see how your LEDs would behave directly in the terminal, without any microcontroller.
4 |
5 | Want to support the development and stay updated?
6 |
7 |
8 |
9 | ## Overview
10 | 1. [Installation](#installation)
11 |
12 | 2. [Example](#example)
13 |
14 | 3. [NeoPixel class](#neopixel-class)
15 |
16 | - [pin](#neopixel_pin)
17 |
18 | - [n](#neopixel_n)
19 |
20 | - [start_led](#neopixel_start_led)
21 |
22 | - [test](#neopixel_test)
23 |
24 | - [overwrite_line](#neopixel_overwrite_line)
25 |
26 | - [debug](#neopixel_debug)
27 |
28 | - [target](#neopixel_target)
29 |
30 |
31 | 4. [NeoPixel functions (animations)](#neopixel-functions-animations)
32 |
33 | 4.1 [rainbow_animation()](#rainbow_animation)
34 |
35 | - [brightness](#rainbow_animation_brightness)
36 |
37 | - [loop_limit](#rainbow_animation_loop_limit)
38 |
39 | - [duration_ms](#rainbow_animation_duration_ms)
40 |
41 | - [pause_ms](#rainbow_animation_pause_ms)
42 |
43 | - [customization_json](#rainbow_animation_customization_json)
44 |
45 | 4.2 [beats()](#beats)
46 |
47 | - [brightness](#beats_brightness)
48 |
49 | - [brightness_fixed](#beats_brightness_fixed)
50 |
51 | - [loop_limit](#beats_loop_limit)
52 |
53 | - [duration_ms](#beats_duration_ms)
54 |
55 | - [pause_ms](#beats_pause_ms)
56 |
57 | - [start](#beats_start)
58 |
59 | - [rgb_colors](#beats_rgb_colors)
60 |
61 | - [num_random_colors](#beats_num_random_colors)
62 |
63 | - [max_height](#beats_num_max_height)
64 |
65 | - [customization_json](#beats_customization_json)
66 |
67 | 4.3 [moving_dot()](#moving_dot)
68 |
69 | - [brightness](#moving_dot_brightness)
70 |
71 | - [loop_limit](#moving_dot_loop_limit)
72 |
73 | - [duration_ms](#moving_dot_duration_ms)
74 |
75 | - [pause_a_ms](#moving_dot_pause_a_ms)
76 |
77 | - [pause_b_ms](#moving_dot_pause_a_ms)
78 |
79 | - [start](#moving_dot_start)
80 |
81 | - [rgb_colors](#moving_dot_rgb_colors)
82 |
83 | - [num_random_colors](#moving_dot_num_random_colors)
84 |
85 | - [customization_json](#moving_dot_customization_json)
86 |
87 | 4.4 [light_up()](#light_up)
88 |
89 | - [brightness](#light_up_brightness)
90 |
91 | - [loop_limit](#light_up_loop_limit)
92 |
93 | - [duration_ms](#light_up_duration_ms)
94 |
95 | - [pause_ms](#light_up_pause_ms)
96 |
97 | - [sections](#light_up_start)
98 |
99 | - [rgb_colors](#light_up_rgb_colors)
100 |
101 | - [num_random_colors](#light_up_num_random_colors)
102 |
103 | - [customization_json](#light_up_customization_json)
104 |
105 | 4.5 [transition()](#transition)
106 |
107 | - [brightness](#transition_brightness)
108 |
109 | - [loop_limit](#transition_loop_limit)
110 |
111 | - [duration_ms](#transition_duration_ms)
112 |
113 | - [pause_ms](#transition_pause_ms)
114 |
115 | - [sections](#transition_start)
116 |
117 | - [rgb_colors](#transition_rgb_colors)
118 |
119 | - [num_random_colors](#transition_num_random_colors)
120 |
121 | - [customization_json](#transition_customization_json)
122 |
123 | 5. [NeoPixel functions (other)](#neopixel-functions-other)
124 |
125 | 5.1 [get_sections()](#get_sections)
126 |
127 | 5.2 [get_led_selectors()](#get_led_selectors)
128 |
129 | - [sections](#get_led_selectors_sections)
130 |
131 | 5.3 [write()](#write)
132 |
133 | - [s_after_wait](#write_s_after_wait)
134 |
135 | 5.4 [get_led()](#get_led)
136 |
137 | - [i](#get_led_i)
138 |
139 | - [start](#get_led_start)
140 |
141 | 5.5 [off()](#off)
142 |
143 | 5.6 [on()](#on)
144 |
145 | - [num](#on_num)
146 |
147 | 5.7 [color()](#color)
148 |
149 | - [rgb_color](#color_rgb_color)
150 |
151 | - [customization_json](#color_customization_json)
152 |
153 | 5.8 [test_animations()](#test_animations)
154 |
155 | 5.9 [get_pin()](#get_pin)
156 |
157 | 6. [Terminal commands](#terminal-commands)
158 |
159 | ## Installation
160 | Make sure Python 3 is installed.
161 |
162 | `Recommended: always create a Python Virtual Environment for your project and install neopixel_plus in that environment.`
163 | ```
164 | pip install neopixel_plus
165 | ```
166 |
167 | ## Example
168 |
169 | IMPORTANT:
170 |
171 | To use NeoPixel+ on Raspberry Pi (using target='adafruit'), you need to make sure you execute python with sudo.
172 | For example:
173 | ```
174 | sudo python
175 | ```
176 | or from a virtual environment
177 | ```
178 | sudo ./pyvenv/bin/python
179 | ```
180 |
181 |
182 | ```
183 | from neopixel_plus import NeoPixel
184 |
185 | # Example 1 - Changing the color of a physical LED
186 | pixel = NeoPixel(pin=5, n=30)
187 | pixel.leds[0] = (219,100,222)
188 | pixel.write()
189 |
190 | # Example 2 - Testing a rainbow animation in the terminal
191 | NeoPixel(test=True).rainbow_animation()
192 |
193 | # Example 3 - Playing a rainbow animation on physical LEDs
194 | NeoPixel(pin=5, n=30).rainbow_animation()
195 |
196 | ```
197 | ## NeoPixel class
198 |
199 | #### Input:
200 |
201 | ##### NeoPixel(pin=...)
202 | ```python
203 | type = int
204 | default = 10
205 | purpose = 'The GPIO pin the data wire of the LED strip is connected to'
206 | ```
207 |
208 | ##### NeoPixel(n=...)
209 | ```python
210 | type = int
211 | default = 30
212 | purpose = 'The number of RGB LEDs on your LED strip'
213 | ```
214 |
215 | ##### NeoPixel(start_led=...)
216 | ```python
217 | type = int
218 | default = 0
219 | purpose = 'With which LED should the animation start'
220 | ```
221 |
222 | ##### NeoPixel(test=...)
223 | ```python
224 | type = bool
225 | default = False
226 | purpose = 'If True: show LED simulation in terminal output. If False: connect to real LED strip and play animation.'
227 | ```
228 |
229 | ##### NeoPixel(overwrite_line=...)
230 | ```python
231 | type = bool
232 | default = True
233 | purpose = 'If False: show all steps of LED animation in terminal ouput. Useful for debugging.'
234 | ```
235 |
236 | ##### NeoPixel(debug=...)
237 | ```python
238 | type = bool
239 | default = False
240 | purpose = 'If True: prints all function calls and their input variables, for better debugging.'
241 | ```
242 |
243 | ##### NeoPixel(target=...)
244 | ```python
245 | type = str
246 | default = 'micropython'
247 | options = ['micropython','adafruit']
248 | purpose = 'Defines what kind of NeoPixel library is targeted: the default micropython NeoPixel or adafruits NeoPixel for Raspberry Pi.'
249 | ```
250 |
251 |
252 | ## NeoPixel functions (animations)
253 |
254 | ### rainbow_animation()
255 | 
256 |
257 | #### Input:
258 |
259 | ##### rainbow_animation(brightness=...)
260 | ```python
261 | type = float
262 | default = 1.0
263 | purpose = 'Set the maximum brightness of the LEDs. 0 == off, 1.0 == 100%'
264 | ```
265 |
266 | ##### rainbow_animation(loop_limit=...)
267 | ```python
268 | type = int
269 | default = None
270 | purpose = 'If set, defines how often animation should repeat, else: animation runs in infinite loop.'
271 | ```
272 |
273 | ##### rainbow_animation(duration_ms=...)
274 | ```python
275 | type = int
276 | default = 1000
277 | purpose = 'Defines many ms should the animation last'
278 | ```
279 |
280 | ##### rainbow_animation(pause_ms=...)
281 | ```python
282 | type = int
283 | default = None
284 | purpose = 'If set, defines if a pause should be made after animation and how long that lasts.'
285 | ```
286 |
287 | ##### rainbow_animation(customization_json=...)
288 | ```python
289 | type = dict
290 | default = {}
291 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"duration_ms":2000}'
292 | ```
293 |
294 |
295 | ### beats()
296 | 
297 |
298 | #### Input:
299 |
300 | ##### beats(brightness=...)
301 | ```python
302 | type = float
303 | default = 1.0
304 | purpose = 'Set the maximum brightness of the LEDs. 0 == off, 1.0 == 100%'
305 | ```
306 |
307 | ##### beats(brightness_fixed=...)
308 | ```python
309 | type = bool
310 | default = False
311 | purpose = 'If False: the brightness will start low and become high at the end. If True: the brightness stays the same during the animation, for all LEDs.'
312 | ```
313 |
314 | ##### beats(loop_limit=...)
315 | ```python
316 | type = int
317 | default = None
318 | purpose = 'If set, defines how often animation should repeat, else: animation runs in infinite loop.'
319 | ```
320 |
321 | ##### beats(duration_ms=...)
322 | ```python
323 | type = int
324 | default = 200
325 | purpose = 'Defines many ms should the animation last'
326 | ```
327 |
328 | ##### beats(pause_ms=...)
329 | ```python
330 | type = int
331 | default = 300
332 | purpose = 'If set, defines if a pause should be made after animation and how long that lasts.'
333 | ```
334 |
335 | ##### beats(start=...)
336 | ```python
337 | type = str
338 | default = 'start'
339 | options = ['start','end','start + end','center']
340 | purpose = 'Defines from where the animation should start'
341 | ```
342 |
343 | ##### beats(rgb_colors=...)
344 | ```python
345 | type = list
346 | default = list of randomly selected RGB colors (example: [[140,140,144],[240,100,0]])
347 | purpose = 'Define what RGB colors the animation will use'
348 | ```
349 |
350 | ##### beats(num_random_colors=...)
351 | ```python
352 | type = int
353 | default = 5
354 | purpose = 'Defines how many random RGB colors the animation will switch between, if no RGB colors are manually defined'
355 | ```
356 |
357 | ##### beats(max_height=...)
358 | ```python
359 | type = float
360 | default = 1.0
361 | purpose = 'Defines how high the beat animation can go. 1.0 == 100% of all LEDs, 0 == no LEDs.'
362 | ```
363 |
364 | ##### beats(customization_json=...)
365 | ```python
366 | type = dict
367 | default = {}
368 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"duration_ms":2000}'
369 | ```
370 |
371 |
372 | ### moving_dot()
373 | 
374 |
375 | #### Input:
376 |
377 | ##### moving_dot(brightness=...)
378 | ```python
379 | type = float
380 | default = 1.0
381 | purpose = 'Set the maximum brightness of the LEDs. 0 == off, 1.0 == 100%'
382 | ```
383 |
384 |
385 | ##### moving_dot(loop_limit=...)
386 | ```python
387 | type = int
388 | default = None
389 | purpose = 'If set, defines how often animation should repeat, else: animation runs in infinite loop.'
390 | ```
391 |
392 | ##### moving_dot(duration_ms=...)
393 | ```python
394 | type = int
395 | default = 200
396 | purpose = 'Defines many ms should the animation last'
397 | ```
398 |
399 | ##### moving_dot(pause_a_ms=...)
400 | ```python
401 | type = int
402 | default = 0
403 | purpose = 'Defines if pause A should be made and how long that lasts.'
404 | ```
405 |
406 | ##### moving_dot(pause_b_ms=...)
407 | ```python
408 | type = int
409 | default = 300
410 | purpose = 'Defines if pause B should be made and how long that lasts.'
411 | ```
412 |
413 | ##### moving_dot(start=...)
414 | ```python
415 | type = str
416 | default = 'start'
417 | options = ['start','end']
418 | purpose = 'Defines from where the animation should start'
419 | ```
420 |
421 | ##### moving_dot(rgb_colors=...)
422 | ```python
423 | type = list
424 | default = list of randomly selected RGB colors (example: [[140,140,144],[240,100,0]])
425 | purpose = 'Define what RGB colors the animation will use'
426 | ```
427 |
428 | ##### moving_dot(num_random_colors=...)
429 | ```python
430 | type = int
431 | default = 5
432 | purpose = 'Defines how many random RGB colors the animation will switch between, if no RGB colors are manually defined'
433 | ```
434 |
435 | ##### moving_dot(customization_json=...)
436 | ```python
437 | type = dict
438 | default = {}
439 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"duration_ms":2000}'
440 | ```
441 |
442 | ### light_up()
443 | 
444 |
445 | #### Input:
446 |
447 | ##### light_up(brightness=...)
448 | ```python
449 | type = float
450 | default = 1.0
451 | purpose = 'Set the maximum brightness of the LEDs. 0 == off, 1.0 == 100%'
452 | ```
453 |
454 |
455 | ##### light_up(loop_limit=...)
456 | ```python
457 | type = int
458 | default = None
459 | purpose = 'If set, defines how often animation should repeat, else: animation runs in infinite loop.'
460 | ```
461 |
462 | ##### light_up(duration_ms=...)
463 | ```python
464 | type = int
465 | default = 200
466 | purpose = 'Defines many ms should the animation last'
467 | ```
468 |
469 | ##### light_up(pause_ms=...)
470 | ```python
471 | type = int
472 | default = 200
473 | purpose = 'Defines if pause should be made and how long that lasts.'
474 | ```
475 |
476 | ##### light_up(sections=...)
477 | ```python
478 | type = str or list
479 | default = 'all'
480 | options = ['all',0,1,2,3]
481 | purpose = 'Defines what sections of the LED strip should glow up (one section is 15 LEDs).'
482 | ```
483 |
484 | ##### light_up(rgb_colors=...)
485 | ```python
486 | type = list
487 | default = list of randomly selected RGB colors (example: [[140,140,144],[240,100,0]])
488 | purpose = 'Define what RGB colors the animation will use'
489 | ```
490 |
491 | ##### light_up(num_random_colors=...)
492 | ```python
493 | type = int
494 | default = 5
495 | purpose = 'Defines how many random RGB colors the animation will switch between, if no RGB colors are manually defined'
496 | ```
497 |
498 | ##### light_up(customization_json=...)
499 | ```python
500 | type = dict
501 | default = {}
502 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"duration_ms":2000}'
503 | ```
504 |
505 | ### transition()
506 | 
507 |
508 | #### Input:
509 |
510 | ##### transition(brightness=...)
511 | ```python
512 | type = float
513 | default = 1.0
514 | purpose = 'Set the maximum brightness of the LEDs. 0 == off, 1.0 == 100%'
515 | ```
516 |
517 | ##### transition(loop_limit=...)
518 | ```python
519 | type = int
520 | default = None
521 | purpose = 'If set, defines how often animation should repeat, else: animation runs in infinite loop.'
522 | ```
523 |
524 | ##### transition(duration_ms=...)
525 | ```python
526 | type = int
527 | default = 200
528 | purpose = 'Defines many ms should the animation last'
529 | ```
530 |
531 | ##### transition(pause_ms=...)
532 | ```python
533 | type = int
534 | default = 200
535 | purpose = 'Defines if pause should be made and how long that lasts.'
536 | ```
537 |
538 | ##### transition(sections=...)
539 | ```python
540 | type = str or list
541 | default = 'all'
542 | options = ['all',0,1,2,3]
543 | purpose = 'Defines what sections of the LED strip should glow up (one section is 15 LEDs).'
544 | ```
545 |
546 | ##### transition(rgb_colors=...)
547 | ```python
548 | type = list
549 | default = list of randomly selected RGB colors (example: [[140,140,144],[240,100,0]])
550 | purpose = 'Define what RGB colors the animation will use'
551 | ```
552 |
553 | ##### transition(num_random_colors=...)
554 | ```python
555 | type = int
556 | default = 5
557 | purpose = 'Defines how many random RGB colors the animation will switch between, if no RGB colors are manually defined'
558 | ```
559 |
560 | ##### transition(customization_json=...)
561 | ```python
562 | type = dict
563 | default = {}
564 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"duration_ms":2000}'
565 | ```
566 |
567 | ## NeoPixel functions (other)
568 |
569 | ### get_sections()
570 | 
571 | Returns a list of all the LED strip sections (length: 15 LEDs per section).
572 |
573 | ### get_led_selectors()
574 | 
575 | Returns a list of all the selector numbers to select specific LEDs in the strip.
576 |
577 | #### Input:
578 |
579 | ##### get_led_selectors(sections=...)
580 | ```python
581 | type = str or list
582 | default = 'all'
583 | options = ['all','random',0,1,2,3]
584 | purpose = 'Defines what sections should be returned.'
585 | ```
586 |
587 | ### write()
588 | 
589 | Makes the LEDs glow in the color you defined. If test==True: simulates how the LEDs would glow.
590 |
591 | #### Input:
592 |
593 | ##### write(s_after_wait=...)
594 | ```python
595 | type = float
596 | default = 1.0/36.0
597 | purpose = 'Defines how many seconds the code should wait after writing the LED status.'
598 | ```
599 |
600 | ### get_led()
601 | 
602 | Get the number of an LED, to select it for changing its color.
603 |
604 | #### Input:
605 |
606 | ##### get_led(i=...)
607 | ```python
608 | type = int
609 | purpose = 'Defines which LED you want to get. If <0: LED from the end will be selected.'
610 | ```
611 |
612 | ##### get_led(start=...)
613 | ```python
614 | type = str
615 | default = None
616 | purpose = 'Defines from where your animation starts. If start==end: LEDs will be counted from the end of the LED strip.'
617 | ```
618 |
619 | ### off()
620 | 
621 | Turns all LEDs off.
622 |
623 | ### on()
624 | 
625 | Turns all or specific LEDs on (make them glow white, 100% brightness).
626 |
627 | #### Input:
628 |
629 | ##### on(num=...)
630 | ```python
631 | type = int
632 | default = None
633 | purpose = 'Turn on only one specific LED.'
634 | ```
635 |
636 | ### color()
637 | 
638 | Turn on all LEDs in a specific RGB color.
639 |
640 | #### Input:
641 |
642 | ##### color(rgb_color=...)
643 | ```python
644 | type = list
645 | purpose = 'Define an [r,g,b] list with the red, green and blue values (from 0-255).'
646 | ```
647 |
648 | ##### color(customization_json=...)
649 | ```python
650 | type = dict
651 | default = {}
652 | purpose = 'If you like, you can also give the customization options via a dict as an imput. Example: {"rgb_color":[100,200,200]}'
653 | ```
654 |
655 | ### test_animations()
656 | 
657 | Run all the different LED animations from NeoPixel+.
658 |
659 | ### get_pin()
660 | Returns the class object for the GPIO pin (micropython's and adafruit's NeoPixel use different classes for that).
661 |
662 | ## Terminal commands
663 | You can also start an animation by calling the neopixel_plus.py file directly via your terminal.
664 |
665 | Example:
666 | ```
667 | python3 neopixel_plus.py -t -d -n -a
668 | ```
--------------------------------------------------------------------------------
/images/beats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/beats.png
--------------------------------------------------------------------------------
/images/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/color.png
--------------------------------------------------------------------------------
/images/get_led.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/get_led.png
--------------------------------------------------------------------------------
/images/get_led_selectors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/get_led_selectors.png
--------------------------------------------------------------------------------
/images/get_sections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/get_sections.png
--------------------------------------------------------------------------------
/images/headerimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/headerimage.jpg
--------------------------------------------------------------------------------
/images/light_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/light_up.png
--------------------------------------------------------------------------------
/images/moving_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/moving_dot.png
--------------------------------------------------------------------------------
/images/off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/off.png
--------------------------------------------------------------------------------
/images/on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/on.png
--------------------------------------------------------------------------------
/images/patreon_button.svg:
--------------------------------------------------------------------------------
1 |
2 |
88 |
--------------------------------------------------------------------------------
/images/rainbow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/rainbow.png
--------------------------------------------------------------------------------
/images/test_animations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/test_animations.png
--------------------------------------------------------------------------------
/images/transition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/transition.png
--------------------------------------------------------------------------------
/images/write.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/glowingkitty/NeoPixelPlus/e3ef4c916b4cb368f890e56128dbdf298a148e58/images/write.png
--------------------------------------------------------------------------------
/neopixel_plus/__init__.py:
--------------------------------------------------------------------------------
1 | from .neopixel_plus import NeoPixel
2 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | from neopixel_plus.animations.beats_up_and_down import BeatsUpAndDown
3 | from neopixel_plus.animations.light_up import LightUp
4 | from neopixel_plus.animations.moving_dot import MovingDot
5 | from neopixel_plus.animations.rainbow import RainbowAnimation
6 | from neopixel_plus.animations.transition import Transition
7 | except ImportError:
8 | from animations.beats_up_and_down import BeatsUpAndDown
9 | from animations.light_up import LightUp
10 | from animations.moving_dot import MovingDot
11 | from animations.rainbow import RainbowAnimation
12 | from animations.transition import Transition
13 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/beats_up_and_down.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | try:
4 | from neopixel_plus.helper import Color
5 | except ImportError:
6 | from helper import Color
7 |
8 |
9 | class BeatsUpAndDown:
10 | def __init__(self,
11 | led_strip,
12 | loop_limit=None,
13 | duration_ms=200,
14 | pause_ms=300,
15 | start='start',
16 | rgb_colors=None,
17 | brightness=1,
18 | brightness_fixed=False,
19 | max_height=1,
20 | num_random_colors=5,
21 | ):
22 | self.led_strip = led_strip
23 | self.loop_limit = loop_limit
24 | self.loops = 0
25 | self.duration_ms = duration_ms
26 | self.pause_ms = pause_ms
27 | self.start = start
28 | self.max_height = max_height
29 |
30 | self.write_wait_time = (
31 | self.duration_ms/2/self.led_strip.addressable_strip_length)/1000
32 |
33 | self.colors = Color(
34 | rgb_colors=rgb_colors,
35 | brightness=brightness,
36 | brightness_fixed=brightness_fixed,
37 | num_random_colors=num_random_colors
38 | )
39 |
40 | if self.start == 'start' or self.start == 'end':
41 | self.led_strip.addressable_strip_length = round(
42 | self.led_strip.strip_length*self.max_height)
43 | self.selected_leds = range(self.led_strip.addressable_strip_length)
44 | self.selected_leds_counter_up = self.led_strip.addressable_strip_length
45 | self.selected_leds_counter_down = round(self.led_strip.addressable_strip_length -
46 | self.selected_leds_counter_up)
47 | else:
48 | self.led_strip.addressable_strip_length = self.led_strip.strip_length
49 | self.selected_leds = range(
50 | round(self.led_strip.addressable_strip_length/2))
51 | self.selected_leds_counter_up = round(self.max_height *
52 | round(self.led_strip.addressable_strip_length/2))
53 | self.selected_leds_counter_down = round(round(
54 | self.led_strip.addressable_strip_length/2)-self.selected_leds_counter_up)
55 |
56 | def color_leds(self):
57 | if self.led_strip.debug:
58 | print('BeatsUpAndDown().color_leds()')
59 |
60 | # color LEDs
61 | for i in self.selected_leds[:self.selected_leds_counter_up]:
62 | # if brightness_fixed==False: set brightness depending on what led is glowing up
63 | if self.colors.brightness_fixed == False:
64 | # led 1: 30% of self.brightness_max
65 | # led 2: 30% of max + (i * 70%/self.led_strip.strip_length)
66 | # last LED: 100% * self.brightness_max
67 | if self.start == 'start + end' or self.start == 'center':
68 | self.colors.brightness = round((0.3*self.colors.brightness_max) +
69 | ((i+1)*(0.7/((self.led_strip.addressable_strip_length*self.max_height)/2))), 2)
70 | else:
71 | self.colors.brightness = round((0.3*self.colors.brightness_max) +
72 | ((i+1)*(0.7/self.led_strip.addressable_strip_length)), 2)
73 | self.colors.correct()
74 |
75 | # "start" option "start & end" and "center"
76 | if self.start == 'end':
77 | i = [-(i+1)]
78 | elif self.start == 'start':
79 | i = [i]
80 | elif self.start == 'start + end':
81 | i = [i, -(i+1)]
82 | elif self.start == 'center':
83 | i = [i+round(self.led_strip.addressable_strip_length/2), -
84 | (i+1)+round(self.led_strip.addressable_strip_length/2)]
85 |
86 | for led in i:
87 | led = self.led_strip.get_led(led, self.start)
88 | self.led_strip.leds[led] = self.colors.selected
89 |
90 | self.led_strip.write(s_after_wait=self.write_wait_time)
91 |
92 | def make_leds_black(self):
93 | if self.led_strip.debug:
94 | print('BeatsUpAndDown().make_leds_black()')
95 |
96 | # then make them black
97 | for i in self.selected_leds[self.selected_leds_counter_down:]:
98 | if self.start == 'start':
99 | i = [-(i+1)]
100 | elif self.start == 'end':
101 | i = [i]
102 | elif self.start == 'start + end':
103 | i = [-(i+1)+round(self.led_strip.addressable_strip_length/2),
104 | i+round(self.led_strip.addressable_strip_length/2)]
105 | elif self.start == 'center':
106 | i = [i, -(i+1)]
107 |
108 | for led in i:
109 | led = self.led_strip.get_led(led, self.start)
110 | self.led_strip.leds[led] = self.colors.black
111 |
112 | self.led_strip.write(s_after_wait=self.write_wait_time)
113 |
114 | def glow(self):
115 | if self.led_strip.debug:
116 | print('BeatsUpAndDown().glow()')
117 |
118 | print('Beats up and down:')
119 | try:
120 | # make sure leds are off
121 | self.led_strip.off()
122 |
123 | while True:
124 | # update color if brightness different
125 | if self.colors.brightness != 1 and self.colors.brightness_fixed:
126 | self.colors.correct()
127 |
128 | self.color_leds()
129 | self.make_leds_black()
130 |
131 | # change to next color
132 | self.colors.next()
133 |
134 | if self.pause_ms:
135 | time.sleep(self.pause_ms/1000)
136 |
137 | self.loops += 1
138 | if self.loop_limit and self.loop_limit == self.loops:
139 | print()
140 | break
141 | except KeyboardInterrupt:
142 | self.led_strip.fadeout()
143 |
144 | import sys
145 | print()
146 | sys.exit(0)
147 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/light_up.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | try:
4 | from neopixel_plus.helper import Color
5 | except ImportError:
6 | from helper import Color
7 |
8 |
9 | class LightUp:
10 | def __init__(self,
11 | led_strip,
12 | rgb_colors=None,
13 | brightness=1,
14 | loop_limit=None,
15 | duration_ms=200,
16 | pause_ms=200,
17 | num_random_colors=5,
18 | sections='all'):
19 | self.led_strip = led_strip
20 | self.loop_limit = loop_limit
21 | self.loops = 0
22 | self.duration_ms = duration_ms
23 | self.pause_ms = pause_ms
24 | self.sections = sections
25 | self.colors = Color(
26 | rgb_colors=rgb_colors,
27 | brightness=brightness,
28 | num_random_colors=num_random_colors
29 | )
30 |
31 | self.write_wait_time = (
32 | self.duration_ms/((round(self.colors.brightness_max, 1)/0.1)*2)/1000)
33 |
34 | def glow(self):
35 | print('Light up:')
36 | try:
37 | # make sure leds are off
38 | self.led_strip.off()
39 |
40 | while True:
41 | # go over levels of brightness from 0 to 1 and
42 | self.colors.brightness = 0
43 | self.colors.correct()
44 |
45 | self.selected_leds = self.led_strip.get_led_selectors(
46 | self.sections)
47 |
48 | # light up in 10 steps
49 | steps = 0
50 | step_height = round(self.colors.brightness_max/10, 2)
51 | while steps < 10:
52 | for i in self.selected_leds:
53 | self.led_strip.leds[i] = self.colors.selected
54 | self.led_strip.write(s_after_wait=self.write_wait_time)
55 |
56 | # update color
57 | self.colors.brightness += step_height
58 | self.colors.correct()
59 | steps += 1
60 |
61 | steps = 0
62 | while steps < 10:
63 | for i in self.selected_leds:
64 | self.led_strip.leds[i] = self.colors.selected
65 | self.led_strip.write(s_after_wait=self.write_wait_time)
66 |
67 | # update color
68 | self.colors.brightness -= step_height
69 | self.colors.correct()
70 | steps += 1
71 |
72 | # change to next color
73 | self.colors.next()
74 |
75 | if self.pause_ms:
76 | time.sleep(self.pause_ms/1000)
77 |
78 | self.loops += 1
79 | if self.loop_limit and self.loop_limit == self.loops:
80 | print()
81 | break
82 |
83 | except KeyboardInterrupt:
84 | self.led_strip.fadeout()
85 |
86 | import sys
87 | print()
88 | sys.exit(0)
89 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/moving_dot.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | try:
4 | from neopixel_plus.helper import Color
5 | except ImportError:
6 | from helper import Color
7 |
8 |
9 | class MovingDot:
10 | def __init__(self,
11 | led_strip,
12 | loop_limit=None,
13 | duration_ms=200,
14 | pause_a_ms=0,
15 | pause_b_ms=300,
16 | start='start',
17 | rgb_colors=None,
18 | brightness=1,
19 | num_random_colors=5):
20 | self.led_strip = led_strip
21 | self.loop_limit = loop_limit
22 | self.loops = 0
23 | self.duration_ms = duration_ms
24 | self.pause_a_ms = pause_a_ms
25 | self.pause_b_ms = pause_b_ms
26 | self.start = start
27 | self.selector = {
28 | "start": [-1, -2, -3, -4, -5],
29 | "end": [0, 1, 2, 3, 4]
30 | }
31 |
32 | self.colors = Color(
33 | rgb_colors=rgb_colors,
34 | brightness=brightness,
35 | num_random_colors=num_random_colors
36 | )
37 |
38 | self.write_wait_time = (
39 | self.duration_ms/2/self.led_strip.strip_length)/1000
40 |
41 | def create_dot(self):
42 | if self.led_strip.debug:
43 | print('MovingDot().create_dot()')
44 |
45 | self.dot = [self.colors.black]*5
46 |
47 | counter = 0
48 | for selected in self.selector[self.start]:
49 | self.colors.brightness = (
50 | 1-(counter*0.225)) * self.colors.brightness_max
51 | self.colors.correct()
52 | self.dot[selected] = self.colors.selected
53 | counter += 1
54 |
55 | def change_direction(self):
56 | if self.led_strip.debug:
57 | print('MovingDot().change_direction()')
58 |
59 | if self.start == 'start':
60 | self.start = 'end'
61 | else:
62 | self.start = 'start'
63 |
64 | def move_dot(self):
65 | if self.led_strip.debug:
66 | print('MovingDot().move_dot()')
67 |
68 | # move dot into view
69 | for selected in self.selector[self.start]:
70 | if self.start == 'start':
71 | self.led_strip.insert_led(0, self.dot[selected])
72 | else:
73 | self.led_strip.append_led(self.dot[selected])
74 | self.led_strip.write(s_after_wait=self.write_wait_time)
75 |
76 | # add black led to front and remove last led, to move dot
77 | while True:
78 | if self.start == 'start':
79 | self.led_strip.insert_led()
80 | else:
81 | self.led_strip.append_led()
82 | self.led_strip.write(s_after_wait=self.write_wait_time)
83 |
84 | # if all leds black, exit loop
85 | for led in self.led_strip.leds:
86 | if led[0] != 0 or led[1] != 0 or led[2] != 0:
87 | break
88 | else:
89 | break
90 |
91 | def glow(self):
92 | if self.led_strip.debug:
93 | print('MovingDot().glow()')
94 |
95 | print('Moving dot:')
96 | try:
97 | # make sure leds are off
98 | self.led_strip.off()
99 |
100 | while True:
101 | # make sure duration is correct
102 | # create dot with tail
103 | self.create_dot()
104 |
105 | # move dot with tail and write
106 | self.move_dot()
107 |
108 | # once dot disappeared at the end: pause_a
109 | time.sleep(self.pause_a_ms/1000)
110 |
111 | # create new dot with tail and move in opposit start
112 | self.change_direction()
113 | self.create_dot()
114 | self.move_dot()
115 | self.change_direction()
116 |
117 | # once dot disappeared at the end: pause_b
118 | time.sleep(self.pause_b_ms/1000)
119 |
120 | # change to next color
121 | self.colors.next()
122 |
123 | self.loops += 1
124 | if self.loop_limit and self.loop_limit == self.loops:
125 | print()
126 | break
127 |
128 | except KeyboardInterrupt:
129 | self.led_strip.fadeout()
130 |
131 | import sys
132 | print()
133 | sys.exit(0)
134 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/rainbow.py:
--------------------------------------------------------------------------------
1 | import math
2 | import time
3 |
4 | # TODO add Color() and simplify code (create rainbow once, then move it)
5 |
6 |
7 | class RainbowAnimation:
8 | def __init__(self,
9 | led_strip,
10 | brightness=1,
11 | loop_limit=None,
12 | duration_ms=1000,
13 | pause_ms=None):
14 | self.led_strip = led_strip
15 | self.brightness_max = brightness
16 | self.loop_limit = loop_limit
17 | self.duration_ms = duration_ms
18 | self.pause_ms = pause_ms
19 |
20 | self.time_passed_ms = 0
21 |
22 | def set_time_passed_ms(self):
23 | if self.led_strip.debug:
24 | print('RainbowAnimation().set_time_passed_ms()')
25 |
26 | # if duration 1000 ms = 17 loops * 60ms
27 | # if duration 500 ms = 8.5 loops 120ms
28 | # if duration 250 ms = 4.25 loops 240ms
29 | # if duration 100 ms = 1.7 loops 600ms
30 | full_duration = 1000
31 | default_rate = 60
32 |
33 | added_ms = (full_duration/self.duration_ms)*default_rate
34 |
35 | self.time_passed_ms += added_ms
36 |
37 | def set_brightness(self, counter, max_counter):
38 | if self.led_strip.debug:
39 | print('RainbowAnimation().set_brightness(counter={},max_counter={})'.format(
40 | counter, max_counter))
41 |
42 | # if counter == 1 => brightness 0.3
43 | # if counter == 2 => brightness 0.6
44 | # if counter == max_counter-1 => brightness 0.3
45 | # if counter == max_counter-2 => brightness 0.6
46 | if self.duration_ms and self.pause_ms and counter == 0:
47 | self.brightness = 0.3*self.brightness_max
48 | elif self.duration_ms and self.pause_ms and counter == 1:
49 | self.brightness = 0.6*self.brightness_max
50 | elif self.duration_ms and self.pause_ms and counter == (max_counter-2):
51 | self.brightness = 0.6*self.brightness_max
52 | elif self.duration_ms and self.pause_ms and counter == (max_counter-1):
53 | self.brightness = 0.3*self.brightness_max
54 | else:
55 | self.brightness = 1*self.brightness_max
56 |
57 | def get_max_counter(self):
58 | if self.led_strip.debug:
59 | print('RainbowAnimation().get_max_counter()')
60 |
61 | # if duration 1000 ms = 17 loops * 60ms
62 | # if duration 500 ms = 8.5 loops 120ms
63 | # if duration 250 ms = 4.25 loops 240ms
64 | # if duration 100 ms = 1.7 loops 600ms
65 | full_duration = 1000
66 | loops = 17
67 |
68 | return round((self.duration_ms/full_duration)*loops)
69 |
70 | def glow(self):
71 | if self.led_strip.debug:
72 | print('RainbowAnimation().glow()')
73 |
74 | print('Rainbow:')
75 | try:
76 | # if duration, need to adapt time_passed to make one full color loop (and then pause if pause set)
77 | # turn LEDs rainbow
78 | counter = 0
79 | loops = 0
80 | max_counter = self.get_max_counter()
81 | while True:
82 | if loops < 10:
83 | self.brightness = (0.1+(loops*0.1))*self.brightness_max
84 | else:
85 | self.set_brightness(counter, max_counter)
86 |
87 | # turn LEDs black (off) for duration of pause
88 | if counter == max_counter:
89 | if self.duration_ms and self.pause_ms:
90 | self.led_strip.off()
91 | time.sleep((self.pause_ms-10)/1000)
92 |
93 | counter = 0
94 | loops += 1
95 |
96 | if self.loop_limit and self.loop_limit == loops:
97 | print()
98 | break
99 |
100 | else:
101 |
102 | self.set_time_passed_ms()
103 | for i in range(self.led_strip.strip_length):
104 | i = self.led_strip.get_led(i)
105 | color = self.rainbow_color(self.time_passed_ms, i,
106 | self.brightness)
107 | self.led_strip.leds[i] = color
108 |
109 | self.led_strip.write()
110 |
111 | counter += 1
112 | loops += 1
113 | except KeyboardInterrupt:
114 | self.led_strip.fadeout()
115 |
116 | import sys
117 | print()
118 | sys.exit(0)
119 |
120 | def rainbow_color(self, t, i, brightness):
121 | if self.led_strip.debug:
122 | print('RainbowAnimation().rainbow_color(t={},i={},brightness={})'.format(
123 | t, i, brightness))
124 |
125 | t = t/1000
126 |
127 | k = t + 0.05 * i
128 |
129 | r = 0.5 + 0.5 * math.cos(6.28318 * (1.0 * k + 0.00))
130 | g = 0.5 + 0.5 * math.cos(6.28318 * (1.0 * k + 0.33))
131 | b = 0.5 + 0.5 * math.cos(6.28318 * (1.0 * k + 0.67))
132 |
133 | r = int(255.0 * r * brightness)
134 | g = int(255.0 * g * brightness)
135 | b = int(255.0 * b * brightness)
136 |
137 | r = r if r < 255 and r > 0 else 255 if r >= 255 else 0
138 | g = g if g < 255 and g > 0 else 255 if g >= 255 else 0
139 | b = b if b < 255 and b > 0 else 255 if b >= 255 else 0
140 | return (r, g, b)
141 |
--------------------------------------------------------------------------------
/neopixel_plus/animations/transition.py:
--------------------------------------------------------------------------------
1 | import time
2 | from os import name
3 |
4 | try:
5 | from neopixel_plus.helper import Color
6 | except ImportError:
7 | from helper import Color
8 |
9 |
10 | class Transition:
11 | def __init__(self,
12 | led_strip,
13 | rgb_colors=None,
14 | brightness=1,
15 | loop_limit=None,
16 | duration_ms=200,
17 | pause_ms=200,
18 | num_random_colors=5,
19 | sections='all'):
20 | self.led_strip = led_strip
21 | self.loop_limit = loop_limit
22 | self.loops = 0
23 | self.duration_ms = duration_ms
24 | self.pause_ms = pause_ms
25 | self.sections = sections
26 | self.colors = Color(
27 | rgb_colors=rgb_colors,
28 | brightness=brightness,
29 | num_random_colors=num_random_colors
30 | )
31 |
32 | self.transition_steps = 20
33 | self.write_wait_time = (self.duration_ms/self.transition_steps)/1000
34 |
35 | self.selected_leds = self.led_strip.get_led_selectors(
36 | self.sections)
37 |
38 | def glow(self):
39 | if self.led_strip.debug:
40 | print('Transition().glow()')
41 |
42 | print('Transition:')
43 | try:
44 | # make sure leds are off
45 | self.led_strip.off()
46 |
47 | while True:
48 | # add or substract difference between rgb values and update color - to make transition
49 |
50 | steps_counter = 0
51 | target_color = self.colors.selected
52 | difference = [
53 | target_color[0] -
54 | self.led_strip.leds[self.selected_leds[0]][0],
55 | target_color[1] -
56 | self.led_strip.leds[self.selected_leds[0]][1],
57 | target_color[2] -
58 | self.led_strip.leds[self.selected_leds[0]][2],
59 | ]
60 |
61 | difference_per_step = [
62 | round(difference[0]/self.transition_steps),
63 | round(difference[1]/self.transition_steps),
64 | round(difference[2]/self.transition_steps),
65 | ]
66 |
67 | while steps_counter != self.transition_steps:
68 |
69 | self.colors.selected = [
70 | self.led_strip.leds[self.selected_leds[0]
71 | ][0]+difference_per_step[0],
72 | self.led_strip.leds[self.selected_leds[0]
73 | ][1]+difference_per_step[1],
74 | self.led_strip.leds[self.selected_leds[0]
75 | ][2]+difference_per_step[2],
76 | ]
77 |
78 | # make to not select invalid RGB values
79 | new_list = []
80 | for number in self.colors.selected:
81 | if number < 0:
82 | new_list.append(0)
83 | elif number > 255:
84 | new_list.append(255)
85 | else:
86 | new_list.append(number)
87 | self.colors.selected = new_list
88 |
89 | for i in self.selected_leds:
90 | self.led_strip.leds[i] = self.colors.selected
91 | self.led_strip.write(s_after_wait=self.write_wait_time)
92 |
93 | steps_counter += 1
94 |
95 | # change to next color
96 | self.colors.next()
97 |
98 | if self.pause_ms:
99 | time.sleep(self.pause_ms/1000)
100 |
101 | self.loops += 1
102 | if self.loop_limit and self.loop_limit == self.loops:
103 | print()
104 | break
105 |
106 | except KeyboardInterrupt:
107 | self.led_strip.fadeout()
108 |
109 | import sys
110 | print()
111 | sys.exit(0)
112 |
--------------------------------------------------------------------------------
/neopixel_plus/helper/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | try:
3 | from neopixel_plus.helper.colors import Color
4 | except ImportError:
5 | from helper.colors import Color
6 |
--------------------------------------------------------------------------------
/neopixel_plus/helper/colors.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 |
4 | class Color:
5 | def __init__(self, rgb_colors, brightness=1, brightness_fixed=False, num_random_colors=5):
6 | self.rgb_colors = rgb_colors if rgb_colors else self.random_set(
7 | num_random_colors)
8 | self.selected_num = 0
9 | self.selected_max = len(self.rgb_colors)-1
10 | # make sure self.rgb_colors is a list and self.rgb_colors[self.selected_num] is also a list
11 | if type(self.rgb_colors) == list and type(self.rgb_colors[self.selected_num]) == list:
12 | self.base_color = self.rgb_colors[self.selected_num]
13 | else:
14 | print(
15 | 'self.rgb_colors and self.rgb_colors[self.selected_num] must be lists. Currently:')
16 | print('self.rgb_colors: {}'.format(self.rgb_colors))
17 | print('self.rgb_colors[self.selected_num]: {}'.format(
18 | self.rgb_colors[self.selected_num]))
19 | raise
20 | self.brightness = brightness
21 | self.brightness_max = brightness
22 | self.brightness_fixed = brightness_fixed
23 |
24 | self.correct()
25 |
26 | @property
27 | def black(self):
28 | return [0, 0, 0]
29 |
30 | @property
31 | def white(self):
32 | return [255, 255, 255]
33 |
34 | def random(self):
35 | return [random.randint(1, 255), random.randint(1, 255), random.randint(1, 255)]
36 |
37 | def random_set(self, how_many):
38 | array = [0]*how_many
39 | return [self.random() for x in array]
40 |
41 | def correct(self):
42 | r = int(self.base_color[0] * self.brightness)
43 | g = int(self.base_color[1] * self.brightness)
44 | b = int(self.base_color[2] * self.brightness)
45 |
46 | self.selected = [r if r < 255 else 255, g if g <
47 | 255 else 255, b if b < 255 else 255]
48 |
49 | def next(self):
50 | # select next color from self.rgb_colors, with correct brightness
51 | if self.selected_num == self.selected_max:
52 | self.selected_num = 0
53 | else:
54 | self.selected_num += 1
55 | self.base_color = self.rgb_colors[self.selected_num]
56 | self.correct()
57 |
--------------------------------------------------------------------------------
/neopixel_plus/neopixel_plus.py:
--------------------------------------------------------------------------------
1 | import getopt
2 | import math
3 | import random
4 | import sys
5 | import time
6 | from random import randint
7 |
8 | try:
9 | from neopixel_plus.animations import *
10 | except ImportError:
11 | from animations import *
12 |
13 |
14 | class NeoPixel:
15 | def __init__(self,
16 | pin_num=None,
17 | n=30,
18 | start_led=0,
19 | test=False,
20 | overwrite_line=True,
21 | debug=False,
22 | target='micropython' # or 'adafruit'
23 | ):
24 | self.debug = debug
25 | self.target = target
26 | self.strip_length = n
27 | self.addressable_strip_length = n
28 | self.start_led = start_led
29 | self.test = test
30 | self.pin_num = pin_num if pin_num else 10 if self.target == 'micropython' else 18 if self.target == 'adafruit' else None
31 | self.overwrite_line = overwrite_line
32 | self.sections = self.get_sections()
33 |
34 | if self.test:
35 | self.leds = [[0, 0, 0] for x in range(self.strip_length)]
36 | else:
37 | from neopixel import NeoPixel as NeoPixelOriginal
38 | if self.target == 'micropython':
39 | self.leds = NeoPixelOriginal(
40 | self.get_pin(),
41 | self.strip_length)
42 | elif self.target == 'adafruit':
43 | self.leds = NeoPixelOriginal(
44 | self.get_pin(),
45 | self.strip_length,
46 | auto_write=False)
47 |
48 | def get_pin(self):
49 | if self.target == 'micropython':
50 | from machine import Pin
51 | return Pin(self.pin_num, Pin.OUT)
52 |
53 | elif self.target == 'adafruit':
54 | import board
55 | if self.pin_num == 18:
56 | return board.D18
57 | elif self.pin_num == 23:
58 | return board.D23
59 | elif self.pin_num == 24:
60 | return board.D24
61 | elif self.pin_num == 24:
62 | return board.D24
63 | elif self.pin_num == 25:
64 | return board.D25
65 | elif self.pin_num == 12:
66 | return board.D12
67 | elif self.pin_num == 16:
68 | return board.D16
69 | elif self.pin_num == 4:
70 | return board.D4
71 | elif self.pin_num == 17:
72 | return board.D17
73 | elif self.pin_num == 27:
74 | return board.D27
75 | elif self.pin_num == 22:
76 | return board.D22
77 | elif self.pin_num == 5:
78 | return board.D5
79 | elif self.pin_num == 6:
80 | return board.D6
81 | elif self.pin_num == 13:
82 | return board.D13
83 | elif self.pin_num == 26:
84 | return board.D26
85 |
86 | def get_sections(self):
87 | if self.debug:
88 | print('NeoPixel().get_sections()')
89 |
90 | sections_length = 15
91 | sections = []
92 | counter = 0
93 | while counter < self.addressable_strip_length:
94 | sections.append(
95 | [x for x in range(counter, counter+sections_length)])
96 | counter += sections_length
97 | return sections
98 |
99 | def get_led_selectors(self, sections='all'):
100 | if self.debug:
101 | print('NeoPixel().get_led_selectors(sections={})'.format(sections))
102 |
103 | if type(sections) == str:
104 | if sections == 'all':
105 | return range(self.addressable_strip_length)
106 | elif sections == 'random':
107 | return self.sections[randint(0, len(self.sections)-1)]
108 | else:
109 | selected_leds = []
110 |
111 | # if "sections" is a list of strings, first convert them to counter numbers (0,1,2,3) instead of "Section 1","Section 2" etc.
112 | if type(sections[0]) == str:
113 | sections = [int(x.lower().replace(' ', '').split(
114 | 'section')[-1])-1 for x in sections]
115 |
116 | for entry in sections:
117 | selected_leds += self.sections[entry]
118 |
119 | return selected_leds
120 |
121 | def write(self, s_after_wait=1.0/36.0):
122 | if self.debug:
123 | print('NeoPixel().write(s_after_wait={})'.format(s_after_wait))
124 |
125 | if self.test:
126 | from colr import color
127 | print(
128 | ''.join(color(' ', back=(x[0], x[1], x[2])) for x in self.leds), end='\r' if self.overwrite_line and not self.debug else '\n')
129 | else:
130 | if self.target == 'micropython':
131 | self.leds.write()
132 | elif self.target == 'adafruit':
133 | self.leds.show()
134 | time.sleep(s_after_wait)
135 |
136 | def insert_led(self, position=0, rgb=[0, 0, 0]):
137 | if self.debug:
138 | print('NeoPixel().insert_led(position={},rgb={})'.format(position, rgb))
139 | # save state of all leds as list, insert LED at position, then write LEDs
140 | leds = [[x[0], x[1], x[2]] for x in self.leds]
141 | leds.insert(position, rgb)
142 | leds = leds[:-1]
143 | for i in range(len(leds)):
144 | self.leds[i] = leds[i]
145 |
146 | def append_led(self, rgb=[0, 0, 0]):
147 | if self.debug:
148 | print('NeoPixel().append_led(rgb={})'.format(rgb))
149 | # save state of all leds as list, append LED at the end, then write LEDs
150 | leds = [[x[0], x[1], x[2]] for x in self.leds]
151 | leds.append(rgb)
152 | leds = leds[1:]
153 | for i in range(len(leds)):
154 | self.leds[i] = leds[i]
155 |
156 | def fadeout(self):
157 | # get current colors of leds and make them darker step by step
158 | brightness = 0.9
159 | while brightness >= 0:
160 | for x in range(self.strip_length):
161 | r = round(self.leds[x][0]*brightness)
162 | g = round(self.leds[x][1]*brightness)
163 | b = round(self.leds[x][2]*brightness)
164 | self.leds[x] = [
165 | r if r <= 255 and r >= 0 else 255 if r > 255 else 0,
166 | g if g <= 255 and g >= 0 else 255 if g > 255 else 0,
167 | b if b <= 255 and b >= 0 else 255 if b > 255 else 0,
168 | ]
169 | brightness -= 0.1
170 | self.write(0.001)
171 |
172 | def get_led(self, i, start=None):
173 | if self.debug:
174 | print('NeoPixel().get_led(i={},start={}'.format(i, start))
175 | i = i+self.start_led
176 | if i < 0:
177 | i += self.addressable_strip_length
178 | if start and start == 'end':
179 | i += (self.strip_length-self.addressable_strip_length)
180 |
181 | return i
182 |
183 | def off(self):
184 | if self.debug:
185 | print('NeoPixel().off()')
186 | for i in range(self.strip_length):
187 | self.leds[i] = (0, 0, 0)
188 | self.write()
189 |
190 | def on(self, num=None):
191 | if self.debug:
192 | print('NeoPixel().on(num={})'.format(num))
193 | if type(num) == int:
194 | num = self.get_led(num)
195 | self.leds[num] = (255, 255, 255)
196 | else:
197 | for i in range(self.strip_length):
198 | self.leds[i] = (255, 255, 255)
199 | self.write()
200 |
201 | def test_animations(self):
202 | # run all the animations for testing
203 | print('Start testing animations...')
204 | while True:
205 | self.rainbow_animation(loop_limit=2)
206 |
207 | self.beats(loop_limit=3)
208 | self.beats(loop_limit=3, start='end')
209 | self.beats(loop_limit=3, start='start + end')
210 | self.beats(loop_limit=3, start='center', brightness=0.5)
211 |
212 | self.moving_dot(loop_limit=3)
213 | self.moving_dot(loop_limit=3, start='end', brightness=0.5)
214 |
215 | self.light_up(loop_limit=3)
216 | self.light_up(loop_limit=3, sections='random')
217 | self.light_up(loop_limit=3, sections=[0])
218 |
219 | self.transition(loop_limit=3)
220 | self.transition(loop_limit=3, sections=[0])
221 |
222 | def color(self,
223 | rgb_colors=[randint(0, 255), randint(0, 255), randint(0, 255)],
224 | customization_json={}
225 | ):
226 | try:
227 | print('color:')
228 | original_r = customization_json['rgb_colors'][0][
229 | 0] if customization_json and 'rgb_colors' in customization_json else rgb_colors[0][0]
230 | original_g = customization_json['rgb_colors'][0][
231 | 1] if customization_json and 'rgb_colors' in customization_json else rgb_colors[0][1]
232 | original_b = customization_json['rgb_colors'][0][
233 | 2] if customization_json and 'rgb_colors' in customization_json else rgb_colors[0][2]
234 |
235 | brightness = 0.1
236 | while brightness <= 1:
237 | for i in range(self.strip_length):
238 |
239 | r = round(original_r*brightness)
240 | g = round(original_g*brightness)
241 | b = round(original_b*brightness)
242 | i = self.get_led(i)
243 | self.leds[i] = [
244 | r if r <= 255 and r >= 0 else 255 if r > 255 else 0,
245 | g if g <= 255 and g >= 0 else 255 if g > 255 else 0,
246 | b if b <= 255 and b >= 0 else 255 if b > 255 else 0,
247 | ]
248 | self.write()
249 | brightness += 0.1
250 |
251 | while True:
252 | # await keyboard interrupt
253 | time.sleep(10)
254 | except KeyboardInterrupt:
255 | self.fadeout()
256 |
257 | import sys
258 | print()
259 | sys.exit(0)
260 |
261 | def rainbow_animation(self,
262 | loop_limit=None,
263 | brightness=1,
264 | duration_ms=1000,
265 | pause_ms=None,
266 | customization_json={}
267 | ):
268 |
269 | RainbowAnimation(
270 | led_strip=self,
271 | loop_limit=customization_json['loop_limit'] if customization_json and 'loop_limit' in customization_json else loop_limit,
272 | brightness=customization_json['brightness'] if customization_json and 'brightness' in customization_json else brightness,
273 | duration_ms=customization_json['duration_ms'] if customization_json and 'duration_ms' in customization_json else duration_ms,
274 | pause_ms=customization_json['pause_ms'] if customization_json and 'pause_ms' in customization_json else pause_ms
275 | ).glow()
276 |
277 | def beats(self,
278 | rgb_colors=None,
279 | brightness=1,
280 | brightness_fixed=False,
281 | max_height=1,
282 | loop_limit=None,
283 | duration_ms=200,
284 | pause_ms=300,
285 | start='start',
286 | num_random_colors=5,
287 | customization_json={}
288 | ):
289 |
290 | BeatsUpAndDown(
291 | led_strip=self,
292 | rgb_colors=customization_json['rgb_colors'] if customization_json and 'rgb_colors' in customization_json else rgb_colors,
293 | brightness=customization_json['brightness'] if customization_json and 'brightness' in customization_json else brightness,
294 | brightness_fixed=customization_json['brightness_fixed'] if customization_json and 'brightness_fixed' in customization_json else brightness_fixed,
295 | max_height=customization_json['max_height'] if customization_json and 'max_height' in customization_json else max_height,
296 | loop_limit=customization_json['loop_limit'] if customization_json and 'loop_limit' in customization_json else loop_limit,
297 | duration_ms=customization_json['duration_ms'] if customization_json and 'duration_ms' in customization_json else duration_ms,
298 | pause_ms=customization_json['pause_ms'] if customization_json and 'pause_ms' in customization_json else pause_ms,
299 | start=customization_json['start'] if customization_json and 'start' in customization_json else start,
300 | num_random_colors=customization_json['num_random_colors'] if customization_json and 'num_random_colors' in customization_json else num_random_colors
301 | ).glow()
302 |
303 | def moving_dot(self,
304 | rgb_colors=None,
305 | brightness=1,
306 | loop_limit=None,
307 | duration_ms=200,
308 | pause_a_ms=0,
309 | pause_b_ms=300,
310 | start='start',
311 | num_random_colors=5,
312 | customization_json={}
313 | ):
314 |
315 | MovingDot(
316 | led_strip=self,
317 | rgb_colors=customization_json['rgb_colors'] if customization_json and 'rgb_colors' in customization_json else rgb_colors,
318 | brightness=customization_json['brightness'] if customization_json and 'brightness' in customization_json else brightness,
319 | loop_limit=customization_json['loop_limit'] if customization_json and 'loop_limit' in customization_json else loop_limit,
320 | duration_ms=customization_json['duration_ms'] if customization_json and 'duration_ms' in customization_json else duration_ms,
321 | pause_a_ms=customization_json['pause_a_ms'] if customization_json and 'pause_a_ms' in customization_json else pause_a_ms,
322 | pause_b_ms=customization_json['pause_b_ms'] if customization_json and 'pause_b_ms' in customization_json else pause_b_ms,
323 | start=customization_json['start'] if customization_json and 'start' in customization_json else start,
324 | num_random_colors=customization_json['num_random_colors'] if customization_json and 'num_random_colors' in customization_json else num_random_colors
325 | ).glow()
326 |
327 | def light_up(self,
328 | rgb_colors=None,
329 | brightness=1,
330 | loop_limit=None,
331 | duration_ms=200,
332 | pause_ms=200,
333 | num_random_colors=5,
334 | sections='all',
335 | customization_json={}
336 | ):
337 |
338 | LightUp(
339 | led_strip=self,
340 | rgb_colors=customization_json['rgb_colors'] if customization_json and 'rgb_colors' in customization_json else rgb_colors,
341 | brightness=customization_json['brightness'] if customization_json and 'brightness' in customization_json else brightness,
342 | loop_limit=customization_json['loop_limit'] if customization_json and 'loop_limit' in customization_json else loop_limit,
343 | duration_ms=customization_json['duration_ms'] if customization_json and 'duration_ms' in customization_json else duration_ms,
344 | pause_ms=customization_json['pause_ms'] if customization_json and 'pause_ms' in customization_json else pause_ms,
345 | num_random_colors=customization_json['num_random_colors'] if customization_json and 'num_random_colors' in customization_json else num_random_colors,
346 | sections=customization_json['sections'] if customization_json and 'sections' in customization_json else sections
347 | ).glow()
348 |
349 | def transition(self,
350 | rgb_colors=None,
351 | brightness=1,
352 | loop_limit=None,
353 | duration_ms=200,
354 | pause_ms=200,
355 | num_random_colors=5,
356 | sections='all',
357 | customization_json={}
358 | ):
359 |
360 | Transition(
361 | led_strip=self,
362 | rgb_colors=customization_json['rgb_colors'] if customization_json and 'rgb_colors' in customization_json else rgb_colors,
363 | brightness=customization_json['brightness'] if customization_json and 'brightness' in customization_json else brightness,
364 | loop_limit=customization_json['loop_limit'] if customization_json and 'loop_limit' in customization_json else loop_limit,
365 | duration_ms=customization_json['duration_ms'] if customization_json and 'duration_ms' in customization_json else duration_ms,
366 | pause_ms=customization_json['pause_ms'] if customization_json and 'pause_ms' in customization_json else pause_ms,
367 | num_random_colors=customization_json['num_random_colors'] if customization_json and 'num_random_colors' in customization_json else num_random_colors,
368 | sections=customization_json['sections'] if customization_json and 'sections' in customization_json else sections
369 | ).glow()
370 |
371 |
372 | if __name__ == "__main__":
373 | test = True
374 | target = None
375 | n = 60
376 | animation = 'rainbow_animation'
377 | customization = {}
378 | try:
379 | opts, args = getopt.getopt(sys.argv[1:], "ht:d:n:a:c:", [
380 | "test=", "target=", "n=", "animation=", "customization="])
381 | except getopt.GetoptError:
382 | print('neopixel_plus.py -t -d -n -a -c ')
383 | sys.exit(2)
384 | for opt, arg in opts:
385 | if opt in ("-t", "--test"):
386 | test = arg
387 | elif opt in ("-d", "--target"):
388 | target = arg
389 | elif opt in ("-n", "--n"):
390 | n = int(arg)
391 | elif opt in ("-a", "--animation"):
392 | animation = arg
393 | elif opt in ("-c", "--customization"):
394 | customization = eval(arg)
395 |
396 | if target:
397 | test = False
398 |
399 | # get parameters and function call from shell commands
400 | getattr(NeoPixel(test=test, target=target, n=n), animation)(
401 | customization_json=customization)
402 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | setuptools.setup(
7 | name="neopixel_plus", # Replace with your own username
8 | version="1.7",
9 | author="Marco",
10 | author_email=None,
11 | description="The NeoPixel library plus animations and terminal testing mode - so you can see how your LEDs would behave directly in the terminal, without any microcontroller.",
12 | long_description=long_description,
13 | long_description_content_type="text/markdown",
14 | url="https://github.com/glowingkitty/NeoPixelPlus",
15 | packages=setuptools.find_packages(),
16 | classifiers=[
17 | "Programming Language :: Python :: 3",
18 | "License :: OSI Approved :: MIT License",
19 | "Operating System :: OS Independent",
20 | ],
21 | python_requires='>=3.6',
22 | install_requires=[
23 | 'colr',
24 | 'rpi_ws281x',
25 | 'adafruit-circuitpython-neopixel'
26 | ]
27 | )
28 |
--------------------------------------------------------------------------------