Inital commit
This commit is contained in:
parent
64374d4477
commit
b165811130
|
@ -0,0 +1,27 @@
|
||||||
|
import network
|
||||||
|
from machine import Pin
|
||||||
|
from config import *
|
||||||
|
|
||||||
|
def do_connect():
|
||||||
|
led = Pin(8, Pin.OUT)
|
||||||
|
sta_if = network.WLAN(network.STA_IF)
|
||||||
|
sta_if.ifconfig((ip, '255.255.255.0', gateway, '1.1.1.1'))
|
||||||
|
if not sta_if.isconnected():
|
||||||
|
print('connecting to network...')
|
||||||
|
sta_if.active(True)
|
||||||
|
sta_if.connect(ssid, password)
|
||||||
|
led.on()
|
||||||
|
while not sta_if.isconnected():
|
||||||
|
pass
|
||||||
|
print('network config:', sta_if.ifconfig())
|
||||||
|
|
||||||
|
do_connect()
|
||||||
|
|
||||||
|
ap = network.WLAN(network.AP_IF)
|
||||||
|
ap.active(True)
|
||||||
|
ap.config(essid="led", password="qwerty1234")
|
||||||
|
print(ap.ifconfig())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>LED Control</title>
|
||||||
|
<script src="main.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Control LEDs</h1>
|
||||||
|
<form id="led_form" method="post" action="/num_leds">
|
||||||
|
<label for="num_leds">Number of LEDs:</label>
|
||||||
|
<input type="text" id="num_leds" name="num_leds" value="{num_leds}">
|
||||||
|
<input type="submit" value="Update">
|
||||||
|
</form>
|
||||||
|
<div id="pattern_buttons">
|
||||||
|
<!-- Pattern buttons will be inserted here -->
|
||||||
|
</div>
|
||||||
|
<form id="delay_form" method="post" action="/delay">
|
||||||
|
<label for="delay">Delay:</label>
|
||||||
|
<input type="range" id="delay" name="delay" min="10" max="1000" value="{delay}" step="10">
|
||||||
|
</form>
|
||||||
|
<form id="color_form" method="post" action="/color">
|
||||||
|
<label for="color">Select Color:</label>
|
||||||
|
<input type="color" id="color" name="color" value="{color}">
|
||||||
|
</form>
|
||||||
|
<form id="color2_form" method="post" action="/color2">
|
||||||
|
<label for="color2">Select Color2:</label>
|
||||||
|
<input type="color" id="color2" name="color2" value="{color2}">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,40 @@
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="range"],
|
||||||
|
input[type="color"],
|
||||||
|
button {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
let delayTimeout;
|
||||||
|
|
||||||
|
async function post(path, value) {
|
||||||
|
console.log(path, value);
|
||||||
|
try {
|
||||||
|
const response = await fetch(path, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: value
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during POST request:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function get(path) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(path);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return await response.json(); // Assuming you are expecting JSON response
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during GET request:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateColor(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const color = document.getElementById('color').value;
|
||||||
|
await post("/color", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateColor2(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const color = document.getElementById('color2').value;
|
||||||
|
await post("/color2", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updatePattern(pattern) {
|
||||||
|
event.preventDefault();
|
||||||
|
await post("/pattern", pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateDelay(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
clearTimeout(delayTimeout);
|
||||||
|
delayTimeout = setTimeout(async function() {
|
||||||
|
const delay = document.getElementById('delay').value;
|
||||||
|
await post('/delay', delay);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateNumLeds(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const numLeds = document.getElementById('num_leds').value;
|
||||||
|
await post('/num_leds', numLeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPatternButtons(patterns) {
|
||||||
|
const container = document.getElementById('pattern_buttons');
|
||||||
|
container.innerHTML = ''; // Clear previous buttons
|
||||||
|
|
||||||
|
patterns.forEach(pattern => {
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.type = 'button'; // Use 'button' instead of 'submit'
|
||||||
|
button.textContent = pattern;
|
||||||
|
button.value = pattern;
|
||||||
|
button.addEventListener('click', async function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
await updatePattern(pattern);
|
||||||
|
});
|
||||||
|
container.appendChild(button);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
|
document.getElementById('color').addEventListener('input', updateColor);
|
||||||
|
document.getElementById('color2').addEventListener('input', updateColor2);
|
||||||
|
document.getElementById('delay').addEventListener('input', updateDelay);
|
||||||
|
document.getElementById('led_form').addEventListener('submit', updateNumLeds);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const patterns = await get("/patterns");
|
||||||
|
console.log('Patterns fetched:', patterns);
|
||||||
|
createPatternButtons(patterns);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching patterns:', error);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,187 @@
|
||||||
|
from machine import Pin
|
||||||
|
from patterns import Patterns
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import json
|
||||||
|
|
||||||
|
class LEDServer:
|
||||||
|
SETTINGS_FILE = "/settings.json" # Path should be adjusted for MicroPython's filesystem
|
||||||
|
|
||||||
|
def __init__(self, num_leds=50, pin=4, led_pin=8, brigtness=255):
|
||||||
|
# Initialize NeoPixel Patterns
|
||||||
|
self.num_leds = num_leds
|
||||||
|
self.patterns = Patterns(pin, num_leds)
|
||||||
|
self.selected_pattern = "blink"
|
||||||
|
self.color = (16, 16, 0)
|
||||||
|
self.color2 = (16, 16, 0)
|
||||||
|
self.delay = 100
|
||||||
|
|
||||||
|
# Initialize single LED
|
||||||
|
self.led = Pin(led_pin, Pin.OUT)
|
||||||
|
|
||||||
|
# Initialize server
|
||||||
|
self.server_socket = socket.socket()
|
||||||
|
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
self.server_socket.bind(('0.0.0.0', 80))
|
||||||
|
self.server_socket.listen(1)
|
||||||
|
self.server_socket.settimeout(1) # Adjust timeout as needed
|
||||||
|
|
||||||
|
self.poll = select.poll()
|
||||||
|
self.poll.register(self.server_socket, select.POLLIN)
|
||||||
|
|
||||||
|
# Load settings from file
|
||||||
|
self.load_settings()
|
||||||
|
# Read static files
|
||||||
|
color = f'#{self.color[0]:02x}{self.color[1]:02x}{self.color[2]:02x}'
|
||||||
|
color2 = f'#{self.color2[0]:02x}{self.color2[1]:02x}{self.color2[2]:02x}'
|
||||||
|
print(color)
|
||||||
|
self.html = self.read_file("/index.html").format(num_leds=self.num_leds, delay=self.delay, color=color, color2=color2).encode()
|
||||||
|
self.js = self.read_file("/main.js").encode('utf-8')
|
||||||
|
self.css = self.read_file("/main.css").encode('utf-8')
|
||||||
|
self.patterns_json = json.dumps(list(self.patterns.patterns.keys()))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def read_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
return file.read()
|
||||||
|
except OSError as e:
|
||||||
|
print(f"Error reading file {file_path}: {e}")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def save_settings(self):
|
||||||
|
settings = {
|
||||||
|
"num_leds": self.num_leds,
|
||||||
|
"selected_pattern": self.selected_pattern,
|
||||||
|
"color": self.color,
|
||||||
|
"color2": self.color2,
|
||||||
|
"delay": self.delay
|
||||||
|
}
|
||||||
|
print(settings)
|
||||||
|
try:
|
||||||
|
with open(self.SETTINGS_FILE, 'w') as file:
|
||||||
|
json.dump(settings, file)
|
||||||
|
except OSError as e:
|
||||||
|
print(f"Error saving settings: {e}")
|
||||||
|
|
||||||
|
def load_settings(self):
|
||||||
|
if self.file_exists(self.SETTINGS_FILE):
|
||||||
|
try:
|
||||||
|
with open(self.SETTINGS_FILE, 'r') as file:
|
||||||
|
settings = json.load(file)
|
||||||
|
self.num_leds = settings.get("num_leds", self.num_leds)
|
||||||
|
self.selected_pattern = settings.get("selected_pattern", self.selected_pattern)
|
||||||
|
self.color = tuple(settings.get("color", self.color))
|
||||||
|
self.color2 = tuple(settings.get("color2", self.color2))
|
||||||
|
self.delay = settings.get("delay", self.delay)
|
||||||
|
self.patterns.update_num_leds(4, self.num_leds)
|
||||||
|
self.patterns.set_delay(self.delay)
|
||||||
|
self.patterns.selected = self.selected_pattern
|
||||||
|
except (OSError, ValueError) as e:
|
||||||
|
print(f"Error loading settings: {e}")
|
||||||
|
|
||||||
|
def file_exists(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r'):
|
||||||
|
return True
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_post(self, path, post_data, client_socket):
|
||||||
|
print(post_data)
|
||||||
|
if path == "/num_leds":
|
||||||
|
try:
|
||||||
|
self.num_leds = int(post_data)
|
||||||
|
self.patterns.update_num_leds(4, self.num_leds)
|
||||||
|
self.save_settings()
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
|
||||||
|
except ValueError:
|
||||||
|
client_socket.send(b'HTTP/1.0 400 Bad request\r\n\r\n')
|
||||||
|
|
||||||
|
elif path == "/pattern":
|
||||||
|
self.selected_pattern = post_data
|
||||||
|
self.patterns.selected = post_data
|
||||||
|
self.save_settings()
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
|
||||||
|
|
||||||
|
elif path == "/delay":
|
||||||
|
try:
|
||||||
|
self.delay = int(post_data)
|
||||||
|
self.patterns.set_delay(self.delay)
|
||||||
|
self.save_settings()
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
|
||||||
|
except ValueError:
|
||||||
|
client_socket.send(b'HTTP/1.0 400 Bad request\r\n\r\n')
|
||||||
|
|
||||||
|
elif path == "/color":
|
||||||
|
# try:
|
||||||
|
self.patterns.set_color1(tuple(int(post_data[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
|
self.save_settings()
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
|
||||||
|
# except:
|
||||||
|
|
||||||
|
# client_socket.send(b'HTTP/1.0 400 Bad request\r\n\r\n')
|
||||||
|
elif path == "/color2":
|
||||||
|
try:
|
||||||
|
self.patterns.set_color2(tuple(int(post_data[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
|
self.save_settings()
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
|
||||||
|
except:
|
||||||
|
client_socket.send(b'HTTP/1.0 400 Bad request\r\n\r\n')
|
||||||
|
else:
|
||||||
|
client_socket.send(b'HTTP/1.0 404 Not Found\r\nContent-Type: text/plain\r\n\r\n')
|
||||||
|
|
||||||
|
def handle_get(self, path, client_socket):
|
||||||
|
if path == "/":
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
|
||||||
|
client_socket.send(self.html)
|
||||||
|
elif path == "/main.js":
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\nContent-type: application/javascript\r\n\r\n')
|
||||||
|
client_socket.send(self.js)
|
||||||
|
elif path == "/main.css":
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\nContent-type: text/css\r\n\r\n')
|
||||||
|
client_socket.send(self.css)
|
||||||
|
elif path == "/patterns":
|
||||||
|
client_socket.send(b'HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n')
|
||||||
|
client_socket.send(self.patterns_json.encode())
|
||||||
|
else:
|
||||||
|
client_socket.send(b'HTTP/1.0 404 Not Found\r\nContent-Type: text/plain\r\n\r\n')
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
count = 0
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
count += 1
|
||||||
|
events = self.poll.poll(1)
|
||||||
|
for file in events:
|
||||||
|
if file[0] == self.server_socket:
|
||||||
|
client_socket, addr = self.server_socket.accept()
|
||||||
|
request = client_socket.recv(1024).decode()
|
||||||
|
method, path, _ = request.split('\r\n')[0].split()
|
||||||
|
print(f"Method: {method}, Path: {path}")
|
||||||
|
if method == "POST":
|
||||||
|
post_data = request.split('\r\n\r\n')[1] if '\r\n\r\n' in request else ''
|
||||||
|
self.handle_post(path, post_data, client_socket)
|
||||||
|
elif method == "GET":
|
||||||
|
self.handle_get(path, client_socket)
|
||||||
|
client_socket.close()
|
||||||
|
|
||||||
|
if count > 50:
|
||||||
|
self.led.off()
|
||||||
|
if count > 100:
|
||||||
|
self.led.on()
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
self.patterns.tick()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Error:", e)
|
||||||
|
finally:
|
||||||
|
self.server_socket.close()
|
||||||
|
self.save_settings()
|
||||||
|
|
||||||
|
# Example of creating and starting the server
|
||||||
|
if __name__ == "__main__":
|
||||||
|
server = LEDServer()
|
||||||
|
server.start()
|
310
patterns.py
310
patterns.py
|
@ -1,114 +1,220 @@
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
from neopixel import NeoPixel
|
from neopixel import NeoPixel
|
||||||
import _thread
|
import utime
|
||||||
import time, math
|
import random
|
||||||
import sys
|
|
||||||
|
|
||||||
class LedPatterns:
|
class Patterns:
|
||||||
def __init__(self, pin, num_leds):
|
def __init__(self, pin, num_leds, color1=(0,0,0), color2=(0,0,0), brightness=127, selected="rainbow_cycle", delay=100):
|
||||||
|
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
|
||||||
self.num_leds = num_leds
|
self.num_leds = num_leds
|
||||||
self.np = NeoPixel(Pin(pin), num_leds)
|
self.pattern_step = 0
|
||||||
self.run = True
|
self.last_update = utime.ticks_ms()
|
||||||
|
self.delay = delay
|
||||||
|
self.brightness = brightness
|
||||||
|
self.patterns = {
|
||||||
|
"color_wipe": self.color_wipe_step,
|
||||||
|
"rainbow_cycle": self.rainbow_cycle_step,
|
||||||
|
"theater_chase": self.theater_chase_step,
|
||||||
|
"blink": self.blink_step,
|
||||||
|
"random_color_wipe": self.random_color_wipe_step,
|
||||||
|
"random_rainbow_cycle": self.random_rainbow_cycle_step,
|
||||||
|
"random_theater_chase": self.random_theater_chase_step,
|
||||||
|
"random_blink": self.random_blink_step,
|
||||||
|
"color_transition": self.color_transition_step # Added color transition pattern
|
||||||
|
}
|
||||||
|
self.selected = selected
|
||||||
|
self.color1 = color1
|
||||||
|
self.color2 = color2
|
||||||
|
self.transition_duration = 5000 # Duration of color transition in milliseconds
|
||||||
|
self.transition_step = 0
|
||||||
|
|
||||||
def color_chase(self, color, wait):
|
def tick(self):
|
||||||
self.run = True
|
self.patterns[self.selected]()
|
||||||
|
|
||||||
|
def update_num_leds(self, pin, num_leds):
|
||||||
|
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
|
||||||
|
self.num_leds = num_leds
|
||||||
|
self.pattern_step = 0
|
||||||
|
|
||||||
|
def set_delay(self, delay):
|
||||||
|
self.delay = delay
|
||||||
|
|
||||||
|
def set_brightness(self, brightness):
|
||||||
|
self.brightness = brightness
|
||||||
|
|
||||||
|
def set_color1(self, color):
|
||||||
|
print(color)
|
||||||
|
self.color1 = self.apply_brightness(color)
|
||||||
|
|
||||||
|
def set_color2(self, color):
|
||||||
|
self.color2 = self.apply_brightness(color)
|
||||||
|
|
||||||
|
def apply_brightness(self, color):
|
||||||
|
return tuple(int(c * self.brightness / 255) for c in color)
|
||||||
|
|
||||||
|
def fill(self):
|
||||||
for i in range(self.num_leds):
|
for i in range(self.num_leds):
|
||||||
self.np[i] = color
|
self.n[i] = self.color1
|
||||||
self.np.write()
|
self.n.write()
|
||||||
if not run:
|
|
||||||
break
|
|
||||||
time.sleep(wait)
|
|
||||||
|
|
||||||
def wheel(self, pos):
|
def color_wipe_step(self):
|
||||||
if pos < 0 or pos > 255:
|
color = self.apply_brightness(self.color1)
|
||||||
return (0, 0, 0)
|
current_time = utime.ticks_ms()
|
||||||
if pos < 85:
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
return (255 - pos * 3, pos * 3, 0)
|
if self.pattern_step < self.num_leds:
|
||||||
if pos < 170:
|
for i in range(self.num_leds):
|
||||||
pos -= 85
|
self.n[i] = (0, 0, 0)
|
||||||
return (0, 255 - pos * 3, pos * 3)
|
self.n[self.pattern_step] = color
|
||||||
pos -= 170
|
self.n.write()
|
||||||
return (pos * 3, 0, 255 - pos * 3)
|
self.pattern_step += 1
|
||||||
|
else:
|
||||||
|
self.pattern_step = 0
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def rainbow_cycle_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
def wheel(pos):
|
||||||
|
if pos < 85:
|
||||||
|
return (pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return (255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return (0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
def rainbow_cycle(self, wait):
|
|
||||||
run = True
|
|
||||||
for j in range(255):
|
|
||||||
for i in range(self.num_leds):
|
for i in range(self.num_leds):
|
||||||
self.np[i] = self.wheel((i * 256 // self.num_leds) + j)
|
rc_index = (i * 256 // self.num_leds) + self.pattern_step
|
||||||
self.np.write()
|
self.n[i] = self.apply_brightness(wheel(rc_index & 255))
|
||||||
if not run:
|
self.n.write()
|
||||||
break
|
self.pattern_step = (self.pattern_step + 1) % 256
|
||||||
time.sleep(wait)
|
self.last_update = current_time
|
||||||
|
|
||||||
def breathing(self, color, duration):
|
def theater_chase_step(self):
|
||||||
steps = 256
|
current_time = utime.ticks_ms()
|
||||||
for _ in range(steps):
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
brightness = int(255 * abs(steps / 2 - _) / (steps / 2))
|
|
||||||
self.np.fill((brightness * color[0] // 255, brightness * color[1] // 255, brightness * color[2] // 255))
|
|
||||||
self.np.write()
|
|
||||||
time.sleep(duration / steps)
|
|
||||||
|
|
||||||
def color_transition(self, start_color, end_color, duration):
|
|
||||||
steps = 256
|
|
||||||
for step in range(steps):
|
|
||||||
color = (
|
|
||||||
int(start_color[0] + (end_color[0] - start_color[0]) * step / steps),
|
|
||||||
int(start_color[1] + (end_color[1] - start_color[1]) * step / steps),
|
|
||||||
int(start_color[2] + (end_color[2] - start_color[2]) * step / steps),
|
|
||||||
)
|
|
||||||
self.np.fill(color)
|
|
||||||
self.np.write()
|
|
||||||
if not self.running():
|
|
||||||
return
|
|
||||||
time.sleep(duration / steps)
|
|
||||||
|
|
||||||
def scanner(self, color, speed):
|
|
||||||
position = 0
|
|
||||||
direction = 1
|
|
||||||
|
|
||||||
while True:
|
|
||||||
self.np.fill((0, 0, 0))
|
|
||||||
self.np[position] = color
|
|
||||||
self.np.write()
|
|
||||||
time.sleep(speed)
|
|
||||||
position += direction
|
|
||||||
if position == self.num_leds - 1 or position == 0:
|
|
||||||
direction *= -1
|
|
||||||
|
|
||||||
def bidirectional_scanner(self, color_left, color_right=None, speed=0.1):
|
|
||||||
color_right = color_right or color_left
|
|
||||||
position_left = 0
|
|
||||||
position_right = self.num_leds - 1
|
|
||||||
direction_left = 1
|
|
||||||
direction_right = -1
|
|
||||||
while True:
|
|
||||||
self.np.fill((0, 0, 0))
|
|
||||||
self.np[position_left] = color_left
|
|
||||||
self.np[position_right] = color_right
|
|
||||||
self.np.write()
|
|
||||||
time.sleep(speed)
|
|
||||||
|
|
||||||
position_left += direction_left
|
|
||||||
position_right += direction_right
|
|
||||||
|
|
||||||
if position_left == self.num_leds - 1 or position_left == 0:
|
|
||||||
direction_left *= -1
|
|
||||||
if position_right == self.num_leds - 1 or position_right == 0:
|
|
||||||
direction_right *= -1
|
|
||||||
|
|
||||||
def sine_wave_propagation(self, color, speed):
|
|
||||||
frequency = 10
|
|
||||||
phase = 0
|
|
||||||
while True:
|
|
||||||
self.np.fill((0, 0, 0))
|
|
||||||
for i in range(self.num_leds):
|
for i in range(self.num_leds):
|
||||||
brightness = int(127.5 * (math.sin(frequency * i + phase) + 1))
|
if (i + self.pattern_step) % 3 == 0:
|
||||||
self.np[i] = (brightness * color[0] // 255, brightness * color[1] // 255, brightness * color[2] // 255)
|
self.n[i] = self.color1
|
||||||
self.np.write()
|
else:
|
||||||
time.sleep(speed)
|
self.n[i] = (0, 0, 0)
|
||||||
phase += 0.1
|
self.n.write()
|
||||||
|
self.pattern_step = (self.pattern_step + 1) % 3
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
def fill(self,color):
|
def blink_step(self):
|
||||||
for i in range(self.num_leds):
|
current_time = utime.ticks_ms()
|
||||||
self.np[i] = color
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
self.np.write()
|
if self.pattern_step % 2 == 0:
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = self.color1
|
||||||
|
else:
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = (0, 0, 0)
|
||||||
|
self.n.write()
|
||||||
|
self.pattern_step = (self.pattern_step + 1) % 2
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def random_color_wipe_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||||
|
if self.pattern_step < self.num_leds:
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = (0, 0, 0)
|
||||||
|
self.n[self.pattern_step] = self.apply_brightness(color)
|
||||||
|
self.n.write()
|
||||||
|
self.pattern_step += 1
|
||||||
|
else:
|
||||||
|
self.pattern_step = 0
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def random_rainbow_cycle_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
def wheel(pos):
|
||||||
|
if pos < 85:
|
||||||
|
return (pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return (255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return (0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
random_offset = random.randint(0, 255)
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
rc_index = (i * 256 // self.num_leds) + self.pattern_step + random_offset
|
||||||
|
self.n[i] = self.apply_brightness(wheel(rc_index & 255))
|
||||||
|
self.n.write()
|
||||||
|
self.pattern_step = (self.pattern_step + 1) % 256
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def random_theater_chase_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
if (i + self.pattern_step) % 3 == 0:
|
||||||
|
self.n[i] = self.apply_brightness(color)
|
||||||
|
else:
|
||||||
|
self.n[i] = (0, 0, 0)
|
||||||
|
self.n.write()
|
||||||
|
self.pattern_step = (self.pattern_step + 1) % 3
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def random_blink_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||||
|
if self.pattern_step % 2 == 0:
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = self.apply_brightness(color)
|
||||||
|
else:
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = (0, 0, 0)
|
||||||
|
self.n.write()
|
||||||
|
self.pattern_step = (self.pattern_step + 1) % 2
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def color_transition_step(self):
|
||||||
|
current_time = utime.ticks_ms()
|
||||||
|
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
||||||
|
# Calculate transition factor based on elapsed time
|
||||||
|
transition_factor = (self.pattern_step * 100) / self.transition_duration
|
||||||
|
if transition_factor > 100:
|
||||||
|
transition_factor = 100
|
||||||
|
color = self.interpolate_color(self.color1, self.color2, transition_factor / 100)
|
||||||
|
|
||||||
|
# Apply the interpolated color to all LEDs
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.n[i] = self.apply_brightness(color)
|
||||||
|
self.n.write()
|
||||||
|
|
||||||
|
self.pattern_step += self.delay
|
||||||
|
if self.pattern_step > self.transition_duration:
|
||||||
|
self.pattern_step = 0
|
||||||
|
|
||||||
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def interpolate_color(self, color1, color2, factor):
|
||||||
|
return (
|
||||||
|
int(color1[0] + (color2[0] - color1[0]) * factor),
|
||||||
|
int(color1[1] + (color2[1] - color1[1]) * factor),
|
||||||
|
int(color1[2] + (color2[2] - color1[2]) * factor)
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
p = Patterns(4, 180)
|
||||||
|
p.set_color1((255,0,0))
|
||||||
|
p.set_color2((0,255,0))
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
for key in p.patterns:
|
||||||
|
print(key)
|
||||||
|
for _ in range(1000):
|
||||||
|
p.tick()
|
||||||
|
utime.sleep_ms(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
p.fill((0, 0, 0))
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
let delayTimeout;
|
||||||
|
|
||||||
|
function post(path, value) {
|
||||||
|
fetch(path, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: encodeURIComponent(value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(path, value) {
|
||||||
|
fetch(path, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColor() {
|
||||||
|
const color = document.getElementById('color').value;
|
||||||
|
post("POST", "/color", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePattern(pattern) {
|
||||||
|
const patternButtons = document.querySelectorAll('button[name="pattern"]');
|
||||||
|
//patternButtons.forEach(button => button.disabled = true);
|
||||||
|
post("/pattern", pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDelay() {
|
||||||
|
clearTimeout(delayTimeout);
|
||||||
|
delayTimeout = setTimeout(function() {
|
||||||
|
const delay = document.getElementById('delay').value;
|
||||||
|
post('/delay', delay);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateNumLeds(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const numLeds = document.getElementById('num_leds').value;
|
||||||
|
post('/num_leds', numLeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.getElementById('color').addEventListener('input', updateColor);
|
||||||
|
document.getElementById('delay').addEventListener('input', updateDelay);
|
||||||
|
document.getElementById('led_form').addEventListener('submit', updateNumLeds);
|
||||||
|
|
||||||
|
const patternButtons = document.querySelectorAll('button[name="pattern"]');
|
||||||
|
patternButtons.forEach(function(button) {
|
||||||
|
button.addEventListener('click', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const pattern = this.value;
|
||||||
|
updatePattern(pattern);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2 {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"], input[type="color"], input[type="range"] {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#delay_value {
|
||||||
|
display: inline-block;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#patterns_radio_buttons label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="range"],
|
||||||
|
input[type="color"],
|
||||||
|
button {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue