neopi 0.1.0__tar.gz
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.
- neopi-0.1.0/PKG-INFO +372 -0
- neopi-0.1.0/README.md +355 -0
- neopi-0.1.0/pyproject.toml +37 -0
- neopi-0.1.0/setup.cfg +4 -0
- neopi-0.1.0/src/neopi/__init__.py +3 -0
- neopi-0.1.0/src/neopi/__main__.py +7 -0
- neopi-0.1.0/src/neopi/animations/__init__.py +79 -0
- neopi-0.1.0/src/neopi/animations/aurora_borealis.py +46 -0
- neopi-0.1.0/src/neopi/animations/blinking_ornaments_1.py +95 -0
- neopi-0.1.0/src/neopi/animations/blinking_ornaments_2.py +123 -0
- neopi-0.1.0/src/neopi/animations/breathing_wreath.py +111 -0
- neopi-0.1.0/src/neopi/animations/chase.py +91 -0
- neopi-0.1.0/src/neopi/animations/color_waves.py +71 -0
- neopi-0.1.0/src/neopi/animations/counterflow_waves.py +90 -0
- neopi-0.1.0/src/neopi/animations/fire_and_ice_bounce.py +54 -0
- neopi-0.1.0/src/neopi/animations/fire_and_ice_duality.py +153 -0
- neopi-0.1.0/src/neopi/animations/fireflies.py +108 -0
- neopi-0.1.0/src/neopi/animations/garland_wave.py +63 -0
- neopi-0.1.0/src/neopi/animations/ghost_procession.py +52 -0
- neopi-0.1.0/src/neopi/animations/gift_unwrapping.py +120 -0
- neopi-0.1.0/src/neopi/animations/glowing_train.py +68 -0
- neopi-0.1.0/src/neopi/animations/hearth_glow.py +68 -0
- neopi-0.1.0/src/neopi/animations/hue_room_bloom.py +56 -0
- neopi-0.1.0/src/neopi/animations/hue_room_chase.py +50 -0
- neopi-0.1.0/src/neopi/animations/hue_room_color_wash.py +49 -0
- neopi-0.1.0/src/neopi/animations/hue_room_mirror_pulse.py +53 -0
- neopi-0.1.0/src/neopi/animations/hue_room_mosaic.py +68 -0
- neopi-0.1.0/src/neopi/animations/hue_room_twinkle.py +42 -0
- neopi-0.1.0/src/neopi/animations/hue_room_waves.py +51 -0
- neopi-0.1.0/src/neopi/animations/marching_stripes.py +76 -0
- neopi-0.1.0/src/neopi/animations/peppermint_swirl.py +86 -0
- neopi-0.1.0/src/neopi/animations/pumpkin_lanterns.py +50 -0
- neopi-0.1.0/src/neopi/animations/rainbow_cycle.py +26 -0
- neopi-0.1.0/src/neopi/animations/shooting_star_chase.py +101 -0
- neopi-0.1.0/src/neopi/animations/snowfall.py +128 -0
- neopi-0.1.0/src/neopi/animations/sparkle.py +109 -0
- neopi-0.1.0/src/neopi/animations/starry_candle_procession.py +146 -0
- neopi-0.1.0/src/neopi/animations/toy_train_parade.py +134 -0
- neopi-0.1.0/src/neopi/animations/twinkle.py +100 -0
- neopi-0.1.0/src/neopi/animations/vampire_drips.py +51 -0
- neopi-0.1.0/src/neopi/animations/witches_cauldron.py +57 -0
- neopi-0.1.0/src/neopi/animations/witching_hour.py +59 -0
- neopi-0.1.0/src/neopi/app.py +1289 -0
- neopi-0.1.0/src/neopi/cli.py +103 -0
- neopi-0.1.0/src/neopi/config.py +182 -0
- neopi-0.1.0/src/neopi/hue.py +457 -0
- neopi-0.1.0/src/neopi/paths.py +18 -0
- neopi-0.1.0/src/neopi/presets.py +1030 -0
- neopi-0.1.0/src/neopi/py.typed +1 -0
- neopi-0.1.0/src/neopi/static/hue.js +75 -0
- neopi-0.1.0/src/neopi/static/index.html +340 -0
- neopi-0.1.0/src/neopi/static/main.js +1098 -0
- neopi-0.1.0/src/neopi/static/style.css +1325 -0
- neopi-0.1.0/src/neopi/type_defs.py +10 -0
- neopi-0.1.0/src/neopi/utils.py +162 -0
- neopi-0.1.0/src/neopi.egg-info/PKG-INFO +372 -0
- neopi-0.1.0/src/neopi.egg-info/SOURCES.txt +64 -0
- neopi-0.1.0/src/neopi.egg-info/dependency_links.txt +1 -0
- neopi-0.1.0/src/neopi.egg-info/entry_points.txt +2 -0
- neopi-0.1.0/src/neopi.egg-info/requires.txt +12 -0
- neopi-0.1.0/src/neopi.egg-info/top_level.txt +1 -0
- neopi-0.1.0/tests/test_color_utils.py +62 -0
- neopi-0.1.0/tests/test_hue.py +223 -0
- neopi-0.1.0/tests/test_hue_animations.py +122 -0
- neopi-0.1.0/tests/test_preview_api.py +28 -0
- neopi-0.1.0/tests/test_refactored.py +79 -0
neopi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: neopi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NeoPixel animation scenes and a friendly Raspberry Pi web controller
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: fastapi<1,>=0.110
|
|
8
|
+
Requires-Dist: pydantic<3,>=2
|
|
9
|
+
Requires-Dist: uvicorn[standard]<1,>=0.29
|
|
10
|
+
Provides-Extra: hardware
|
|
11
|
+
Requires-Dist: Adafruit-Blinka>=8; extra == "hardware"
|
|
12
|
+
Requires-Dist: adafruit-circuitpython-neopixel>=6; extra == "hardware"
|
|
13
|
+
Requires-Dist: rpi-ws281x>=5; extra == "hardware"
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
16
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
17
|
+
|
|
18
|
+
# NeoPi: NeoPixel Animations and Web Controls
|
|
19
|
+
|
|
20
|
+
NeoPi runs customizable seasonal animations on Raspberry Pi NeoPixel lightstrips and provides a responsive local web dashboard. It also includes a simulator fallback for development without LED hardware.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
On a Raspberry Pi with Python 3.9 or newer:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python3 -m venv .venv
|
|
28
|
+
source .venv/bin/activate
|
|
29
|
+
python -m pip install -e ".[hardware]"
|
|
30
|
+
neopi setup
|
|
31
|
+
sudo .venv/bin/neopi serve
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The setup command asks only for the pixel count, strip color order, and GPIO data pin. Then open `http://<your-pi-hostname>:8000` on a device connected to the same network. The dashboard includes a sampled live preview of the animation being sent to the strip.
|
|
35
|
+
|
|
36
|
+
For development on a computer without LEDs:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m pip install -e ".[dev]"
|
|
40
|
+
neopi setup
|
|
41
|
+
neopi serve --reload
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The simulator is selected automatically off the Pi. To choose it explicitly, set `NEOPI_DRIVER=simulator`.
|
|
45
|
+
|
|
46
|
+
After changing branches or pulling packaging changes, refresh the editable install:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python -m pip install -e ".[dev]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The supported installed entry point is `neopi serve`. To run a small animation loop without the web dashboard, use `python example_serverless.py` from a source checkout.
|
|
53
|
+
|
|
54
|
+
> **Hardware safety:** Long strips need a separate, correctly sized 5 V supply. Connect the Pi and supply grounds together; do not power a long strip from the Pi's 5 V pin. A level shifter, 300–500 ohm data resistor, and 500–1000 µF capacitor at the strip input are strongly recommended. Begin with power disconnected and verify DIN, 5 V, and ground before starting the server.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Repository and Package Architecture
|
|
59
|
+
|
|
60
|
+
NeoPi uses a `src` layout so tests and development commands exercise the same importable package that is installed from a wheel:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
neopi/
|
|
64
|
+
├── pyproject.toml
|
|
65
|
+
├── README.md
|
|
66
|
+
├── example_serverless.py # Small animation loop without the web server
|
|
67
|
+
├── src/neopi/
|
|
68
|
+
│ ├── app.py # FastAPI application and controller
|
|
69
|
+
│ ├── cli.py # neopi command
|
|
70
|
+
│ ├── config.py # Hardware initialization and simulator
|
|
71
|
+
│ ├── hue.py # Philips Hue synchronization
|
|
72
|
+
│ ├── presets.py # Preset catalog
|
|
73
|
+
│ ├── animations/ # One module per animation
|
|
74
|
+
│ └── static/ # Dashboard assets bundled in the wheel
|
|
75
|
+
└── tests/
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Installation & Requirements
|
|
81
|
+
|
|
82
|
+
To run this server and correctly interface with the physical lightstrip on your Raspberry Pi, you need the following Python libraries installed:
|
|
83
|
+
|
|
84
|
+
1. **Web Server & API Libraries:**
|
|
85
|
+
* `fastapi` (for the REST/WebSocket API)
|
|
86
|
+
* `uvicorn[standard]` (the ASGI server to run FastAPI)
|
|
87
|
+
* `pydantic` (for data validation)
|
|
88
|
+
|
|
89
|
+
2. **Hardware Control Libraries:**
|
|
90
|
+
* `adafruit-circuitpython-neopixel` (provides the `neopixel` module to control the LEDs)
|
|
91
|
+
* `Adafruit-Blinka` (provides the `board` module to map the physical Raspberry Pi GPIO pins)
|
|
92
|
+
* `rpi-ws281x` (the underlying hardware driver required for WS2812B/NeoPixels on the Pi)
|
|
93
|
+
|
|
94
|
+
The recommended editable install records and installs these dependencies for you:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
python -m pip install -e ".[hardware]"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For a regular local installation or a distributable wheel:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python -m pip install ".[hardware]"
|
|
104
|
+
python -m pip wheel . --no-deps --wheel-dir dist
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The resulting `neopi-*.whl` contains the Python server, built-in animations, and dashboard assets. Once the project is published to a package index, the intended installation command is `python -m pip install "neopi[hardware]"`.
|
|
108
|
+
|
|
109
|
+
To build and publish both the source distribution and wheel from Windows, use the release script. Configure a PyPI token when Twine prompts for credentials:
|
|
110
|
+
|
|
111
|
+
```bat
|
|
112
|
+
publish.cmd
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Configuration and controller state are stored in `~/.config/neopi/`. Set `NEOPI_DATA_DIR` to choose another directory, or override individual files with `NEOPI_CONFIG_FILE`, `NEOPI_SETTINGS_FILE`, and `NEOPI_HUE_SETTINGS_FILE`. Re-run `neopi setup` whenever the strip is replaced or moved to another supported GPIO pin. Controlling NeoPixels on Raspberry Pi commonly requires root privileges, so the production command may need `sudo .venv/bin/neopi serve`.
|
|
116
|
+
|
|
117
|
+
Existing checkout-local `lightstrip_config.json`, `settings.json`, and `hue_settings.json` files are not moved automatically. Copy their contents into `~/.config/neopi/config.json`, `~/.config/neopi/settings.json`, and `~/.config/neopi/hue.json`, respectively, or point the corresponding environment variables at the existing files.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Setting Up as a System Service (Raspberry Pi/Linux)
|
|
122
|
+
|
|
123
|
+
To ensure NeoPi starts automatically when the Raspberry Pi boots and restarts after a failure, configure it as a systemd service.
|
|
124
|
+
|
|
125
|
+
### 1. Create a Service File
|
|
126
|
+
On your Raspberry Pi, create a new file for your service in the `/etc/systemd/system/` directory:
|
|
127
|
+
```bash
|
|
128
|
+
sudo nano /etc/systemd/system/neopi.service
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 2. Add the Configuration
|
|
132
|
+
Replace `yourusername` and the virtual-environment path with the values from your installation.
|
|
133
|
+
|
|
134
|
+
```ini
|
|
135
|
+
[Unit]
|
|
136
|
+
Description=NeoPi lightstrip server
|
|
137
|
+
After=network.target
|
|
138
|
+
|
|
139
|
+
[Service]
|
|
140
|
+
# The user you are running the script as (e.g., 'pi' or your custom username)
|
|
141
|
+
User=yourusername
|
|
142
|
+
|
|
143
|
+
Environment=NEOPI_DATA_DIR=/home/yourusername/.config/neopi
|
|
144
|
+
ExecStart=/home/yourusername/neopi/.venv/bin/neopi serve
|
|
145
|
+
|
|
146
|
+
# Restart the service automatically if it crashes
|
|
147
|
+
Restart=always
|
|
148
|
+
# Wait 5 seconds before restarting
|
|
149
|
+
RestartSec=5
|
|
150
|
+
|
|
151
|
+
# Forward outputs to the system journal
|
|
152
|
+
StandardOutput=inherit
|
|
153
|
+
StandardError=inherit
|
|
154
|
+
|
|
155
|
+
[Install]
|
|
156
|
+
# Starts the service on boot
|
|
157
|
+
WantedBy=multi-user.target
|
|
158
|
+
```
|
|
159
|
+
*(Press `Ctrl+O` then `Enter` to save, and `Ctrl+X` to exit nano).*
|
|
160
|
+
|
|
161
|
+
### 3. Enable and Start the Service
|
|
162
|
+
Reload the systemd daemon to recognize the new file, enable it to start on boot, and start it immediately:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Reload systemd to recognize your new service file
|
|
166
|
+
sudo systemctl daemon-reload
|
|
167
|
+
|
|
168
|
+
# Enable the service to run automatically on boot
|
|
169
|
+
sudo systemctl enable neopi.service
|
|
170
|
+
|
|
171
|
+
# Start the service right now
|
|
172
|
+
sudo systemctl start neopi.service
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 4. Check the Status and Logs
|
|
176
|
+
To verify that your server is running successfully:
|
|
177
|
+
```bash
|
|
178
|
+
sudo systemctl status neopi.service
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
To view the live application logs:
|
|
182
|
+
```bash
|
|
183
|
+
sudo journalctl -u neopi.service -f
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 5. If You Need to Stop or Restart the Service
|
|
187
|
+
```bash
|
|
188
|
+
# To stop the service
|
|
189
|
+
sudo systemctl stop neopi.service
|
|
190
|
+
# To restart the service after installing changes
|
|
191
|
+
sudo systemctl restart neopi.service
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Control Center Web Dashboard Features
|
|
197
|
+
|
|
198
|
+
The NeoPi Control Center is a responsive single-page application for mobile and desktop browsers:
|
|
199
|
+
|
|
200
|
+
1. **Decoupled Animation Preview and Customization**: Clicking on any card in the library selects it, showing its specific configurable sliders in the "Configure & Play" settings panel without immediately playing it. The user can adjust parameters first, then click "Play Now" or "+ Queue" to execute.
|
|
201
|
+
2. **Interactive Live Parameter Tuning**: If the selected card is the currently active manual animation, dragging sliders or choosing colors immediately pushes live REST updates to the Raspberry Pi, showing immediate hardware feedback.
|
|
202
|
+
3. **Dynamic Hover Tooltips**: Every parameter (e.g., frame wait times, segment counts, speeds, spacing) has custom tooltips. Hovering over a slider or input group expands a micro-description explaining exactly how it affects the visual pattern.
|
|
203
|
+
4. **Customizable Auto-Cycle Queue**: Users can choose to run the lightstrip autonomously using a customized sequence list. Queued patterns can be added, deleted, or reordered instantly. Settings are persisted in the NeoPi data directory so that they survive a system restart.
|
|
204
|
+
5. **Global Fade Transitions and Cycling Times**: Users can set how long each auto-cycle animation runs (Active Animation Duration) and how long they fade into one another (Transition Fade Time) using global sliders.
|
|
205
|
+
6. **Restore Defaults Action**: A dedicated action button that instantly restores uvicorn state, cycle modes, parameters, active duration settings, and the default holiday queue back to factory defaults.
|
|
206
|
+
7. **Full RGBW Color & White Channel Control**: Complete 4-channel LED control is supported. The frontend dynamically renders a companion White intensity slider (0-255) next to the color wheel picker for any pattern with an RGBW color parameter. Color values are serialized and transmitted in an extended 8-character hex format (#RRGGBBWW), allowing granular tuning of white channel intensity alongside RGB colors.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Guiding Principles for Writing Animations
|
|
211
|
+
|
|
212
|
+
To maintain consistency, safety, and visual quality, every animation must adhere to these guidelines:
|
|
213
|
+
|
|
214
|
+
### 1. Standard Parameters and Signature
|
|
215
|
+
Every animation function must accept at least these two arguments to ensure compatibility with the automated cycle loop and the web control server:
|
|
216
|
+
* `wait` (float): The speed controller. It is the time in seconds to sleep between rendering frames.
|
|
217
|
+
* `duration` (int or float): The total time in seconds the animation should run before returning.
|
|
218
|
+
|
|
219
|
+
Example signature:
|
|
220
|
+
```python
|
|
221
|
+
def my_new_animation(wait=0.05, duration=10, speed_multiplier=1.0, color=(255, 0, 0, 0)):
|
|
222
|
+
# ... implementation ...
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 2. Documentation Guidelines
|
|
226
|
+
We use the Google Python Style Guide for docstrings. Every animation module must specify:
|
|
227
|
+
1. A summary line describing the visual effect.
|
|
228
|
+
2. A detailed description of the physical look.
|
|
229
|
+
3. An Args section detailing every parameter.
|
|
230
|
+
|
|
231
|
+
Example:
|
|
232
|
+
```python
|
|
233
|
+
def starry_sky(wait=0.1, duration=15, star_count=10):
|
|
234
|
+
"""Simulates glowing stars fading in and out on a dark blue background.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
wait (float): Time to sleep between frames (seconds).
|
|
238
|
+
duration (int): Total run time of the animation (seconds).
|
|
239
|
+
star_count (int): Maximum number of concurrent stars to render.
|
|
240
|
+
"""
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 3. Parametrization and Avoiding Magic Numbers
|
|
244
|
+
* Never use hardcoded magic numbers for speeds, counts, densities, or colors in the rendering loop.
|
|
245
|
+
* Expose these variables as default argument parameters on the function signature.
|
|
246
|
+
* This enables the FastAPI web server to dynamically inspect the function signature using reflection (inspect module) and automatically render customization sliders on the web control panel.
|
|
247
|
+
|
|
248
|
+
### 4. RGBW Color Parameter Formatting
|
|
249
|
+
Color parameters can be defined as 3-channel RGB tuples `(R, G, B)` or 4-channel RGBW tuples `(R, G, B, W)`. The backend parses these into hex values for web interface compatibility:
|
|
250
|
+
* Standard 6-character hex (`#RRGGBB`): Default for standard RGB strips.
|
|
251
|
+
* Extended 8-character hex (`#RRGGBBWW`): Utilized for RGBW strips to package both the color and the white channel intensity. The server automatically translates `#RRGGBBWW` strings back into `(R, G, B, W)` tuples for the animation functions, allowing native hardware integration.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Anti-Flickering Guidelines (CRITICAL)
|
|
256
|
+
|
|
257
|
+
To prevent data line interference, voltage drops, and visual flickering on long strips (e.g., our 289-pixel strip), **don't update all pixels in a single frame**.
|
|
258
|
+
|
|
259
|
+
### Rules for Implementation:
|
|
260
|
+
1. **Interlacing (Stepped Ranges)**: Stagger updates between frames using a stepped range based on the frame parity.
|
|
261
|
+
```python
|
|
262
|
+
# Correct way to loop through pixels
|
|
263
|
+
for i in range(frame % 2, NUM_PIXELS, 2):
|
|
264
|
+
pixels[i] = (r, g, b, w)
|
|
265
|
+
```
|
|
266
|
+
2. **Conditional Drawing**: If calculating a single moving object (e.g., a train engine or comet head), only write to it if it matches the current frame's parity.
|
|
267
|
+
```python
|
|
268
|
+
if pixel_index % 2 == frame % 2:
|
|
269
|
+
pixels[pixel_index] = color
|
|
270
|
+
```
|
|
271
|
+
3. **No pixels.fill() inside rendering loops**: Avoid filling the entire strip in every frame. Clear old pixels in two staggered passes or clear pixels individually using the interlaced frame parity.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Step-by-Step: Adding a New Animation
|
|
276
|
+
|
|
277
|
+
Adding a new custom animation is clean and straightforward:
|
|
278
|
+
|
|
279
|
+
### Step 1: Create the Animation File
|
|
280
|
+
Create a new file in `src/neopi/animations/`, e.g., `my_custom_pattern.py`.
|
|
281
|
+
Import necessary items from `neopi.config` and `neopi.utils`:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
import time
|
|
285
|
+
from neopi.config import pixels, NUM_PIXELS
|
|
286
|
+
from neopi.utils import fade_transition
|
|
287
|
+
|
|
288
|
+
@fade_transition() # Optional: Adds standard fade-out/fade-in between animations
|
|
289
|
+
def my_custom_pattern(wait=0.05, duration=10, main_color=(255, 0, 128, 0)):
|
|
290
|
+
"""A beautiful neon-pink wave sweeping down the strip.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
wait (float): Time to sleep between frames.
|
|
294
|
+
duration (int): Total run time in seconds.
|
|
295
|
+
main_color (tuple): The RGBW color of the sweeping wave.
|
|
296
|
+
"""
|
|
297
|
+
start_time = time.time()
|
|
298
|
+
frame = 0
|
|
299
|
+
|
|
300
|
+
while time.time() - start_time < duration:
|
|
301
|
+
# Use anti-flicker interlaced rendering
|
|
302
|
+
for i in range(frame % 2, NUM_PIXELS, 2):
|
|
303
|
+
# ... rendering logic ...
|
|
304
|
+
pixels[i] = main_color
|
|
305
|
+
|
|
306
|
+
pixels.show()
|
|
307
|
+
time.sleep(wait)
|
|
308
|
+
frame += 1
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Step 2: Register the Animation
|
|
312
|
+
Open `src/neopi/animations/__init__.py`:
|
|
313
|
+
1. Import your new function:
|
|
314
|
+
```python
|
|
315
|
+
from .my_custom_pattern import my_custom_pattern
|
|
316
|
+
```
|
|
317
|
+
2. Add it to the central `ANIMATIONS` registry dictionary:
|
|
318
|
+
```python
|
|
319
|
+
ANIMATIONS = {
|
|
320
|
+
...
|
|
321
|
+
"my_custom_pattern": my_custom_pattern,
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Step 3: Run / Verify
|
|
326
|
+
Run the test suite to verify your function executes correctly without syntax or parameter errors:
|
|
327
|
+
```bash
|
|
328
|
+
python -m pytest
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Registering the animation makes it available in the web dashboard. For a minimal serverless installation, import it in `example_serverless.py` and add it to `run_serverless_cycle()`.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Running Without the Web Server
|
|
336
|
+
|
|
337
|
+
The source checkout includes a minimal loop with Rainbow Cycle, Color Waves, and Counterflow Waves:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
python example_serverless.py
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
It uses the same NeoPi configuration and hardware driver as the installed package, but it does not start FastAPI, save a queue, or synchronize with Philips Hue. Press `Ctrl+C` to stop and blank the strip. Edit the imported functions and calls in `run_serverless_cycle()` to choose a different small set of animations.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Offline Local Development (Mock Mode)
|
|
348
|
+
|
|
349
|
+
If you are not running the code on a Raspberry Pi (e.g., developing on Windows or macOS), the package will **automatically fall back to Mock mode**:
|
|
350
|
+
* It bypasses the physical `board` and `neopixel` hardware libraries.
|
|
351
|
+
* It initializes a `MockNeoPixel` class that matches the interface of the Adafruit library.
|
|
352
|
+
* This allows you to run, test, and develop the FastAPI Web Server and the responsive dashboard locally on your development machine before deploying.
|
|
353
|
+
|
|
354
|
+
## Philips Hue room color sync
|
|
355
|
+
|
|
356
|
+
1. Start the server and open **Hue Room Sync** in the dashboard.
|
|
357
|
+
2. Enter the Hue Bridge's LAN IP address (reserve it in your router to keep it stable).
|
|
358
|
+
3. Press the physical bridge link button, then click **Pair Bridge** within its pairing window.
|
|
359
|
+
4. Load rooms, choose a room or zone, select a palette mode, enable sync, and save. The refresh interval defaults to **10 seconds** and accepts **5–3600 seconds**.
|
|
360
|
+
5. Open the **Hue** library filter and play or queue any of the seven room-aware animations. In addition to Waves, Chase, and Twinkle, the library includes Color Wash, Bloom, Mirror Pulse, and Mosaic. Adjust **Wait** and **Motion Speed** in Configure & Play independently of the bridge refresh interval.
|
|
361
|
+
|
|
362
|
+
All seven Hue animations continuously read a shared palette and blend toward changed colors without restarting their motion or cycle duration. A background worker reads one bridge snapshot per interval, regardless of bulb count. It samples the selected room's individual powered-on, reachable bulbs, including xy colors, hue/saturation, and white color temperature. Global strip brightness remains separately adjustable.
|
|
363
|
+
|
|
364
|
+
**Inferred scene colors** groups perceptually similar bulb readings and exposes up to five representative colors. A nearly uniform room produces one color, while multicolor scenes retain their major color families and isolated contrasting accents. Representatives are actual bulb readings rather than averaged colors. **Direct bulb colors** preserves the original behavior and exposes every exact unique bulb color in the room's bridge order.
|
|
365
|
+
|
|
366
|
+
If the bridge is unavailable, the room is removed, or all its bulbs are off/unreachable, the last usable palette remains active and status explains the condition. Before the first successful sync, the Hue animations use a violet/green/orange fallback. Disabling sync clears the cached palette. Other animation categories continue using their own colors. For uninterrupted manual playback, disable the existing **Auto-Return to Cycle** option.
|
|
367
|
+
|
|
368
|
+
This integration uses the bridge's local **v1 REST API**, following the [official Hue pairing workflow](https://developers.meethue.com/develop/get-started-2/). Bulbs must belong to a Hue Bridge; direct Bluetooth or Zigbee bulb pairing is not implemented. It samples current bulb states rather than extracting every color from a named Hue scene, and does not change Hue bulb state. A dynamic Hue scene is sampled at your chosen interval. Colors are an RGB approximation and can differ between Hue bulbs and your strip.
|
|
369
|
+
|
|
370
|
+
Pairing credentials and Hue settings stay server-side in the NeoPi data directory, separate from ordinary animation settings. The local v1 transport uses HTTP, so use it on your trusted LAN. Bridge addresses are restricted to LAN IP literals; redirects and system HTTP proxies are disabled. **Restore Defaults** also clears local Hue settings; it does not revoke the previously created application user on the bridge.
|
|
371
|
+
|
|
372
|
+
Regression checks: `python -m pytest`. Hue tests mock bridge responses; physical bridge/LED validation is still needed on the Pi.
|