diff --git a/index.html b/index.html
index 6db7767..b557c99 100644
--- a/index.html
+++ b/index.html
@@ -1,31 +1,60 @@
-
+
+
+
LED Control
-
+
+
Control LEDs
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/main.css b/main.css
index 7b3d403..0c393e7 100644
--- a/main.css
+++ b/main.css
@@ -1,40 +1,74 @@
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;
-}
+ font-family: Arial, sans-serif;
+ max-width: 600px;
+ margin: 0 auto;
+ padding: 20px;
+ line-height: 1.6;
+ }
+ h1 {
+ text-align: center;
+ }
+ form {
+ margin-bottom: 20px;
+ }
+ label {
+ display: block;
+ margin-bottom: 5px;
+ }
+ input[type="text"], input[type="submit"], input[type="range"], input[type="color"] {
+ width: 100%;
+
+ margin-bottom: 10px;
+ box-sizing: border-box;
+ }
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ height: 25px;
+ background: #d3d3d3;
+ outline: none;
+ opacity: 0.7;
+ transition: opacity .2s;
+ }
+ input[type="range"]:hover {
+ opacity: 1;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 25px;
+ height: 25px;
+ background: #4CAF50;
+ cursor: pointer;
+ border-radius: 50%;
+ }
+ input[type="range"]::-moz-range-thumb {
+ width: 25px;
+ height: 25px;
+ background: #4CAF50;
+ cursor: pointer;
+ border-radius: 50%;
+ }
+ #pattern_buttons {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 20px;
+ }
+ #pattern_buttons button {
+ flex: 1 0 calc(33.333% - 10px);
+ padding: 10px;
+ background-color: #4CAF50;
+ color: white;
+ border: none;
+ cursor: pointer;
+ transition: background-color 0.3s;
+ }
+ #pattern_buttons button:hover {
+ background-color: #45a049;
+ }
+ @media (max-width: 480px) {
+ #pattern_buttons button {
+ flex: 1 0 calc(50% - 10px);
+ }
+ }
\ No newline at end of file
diff --git a/main.js b/main.js
index e601f25..b33fcd7 100644
--- a/main.js
+++ b/main.js
@@ -1,4 +1,7 @@
let delayTimeout;
+let brightnessTimeout;
+let colorTimeout;
+let color2Timeout;
async function post(path, value) {
console.log(path, value);
@@ -32,14 +35,20 @@ async function get(path) {
async function updateColor(event) {
event.preventDefault();
- const color = document.getElementById('color').value;
- await post("/color", color);
+ clearTimeout(colorTimeout);
+ colorTimeout = setTimeout(async function() {
+ const color = document.getElementById('color').value;
+ await post("/color", color);
+ }, 500);
}
async function updateColor2(event) {
event.preventDefault();
- const color = document.getElementById('color2').value;
- await post("/color2", color);
+ clearTimeout(color2Timeout);
+ color2Timeout = setTimeout(async function() {
+ const color = document.getElementById('color2').value;
+ await post("/color2", color);
+ }, 500);
}
async function updatePattern(pattern) {
@@ -47,6 +56,15 @@ async function updatePattern(pattern) {
await post("/pattern", pattern);
}
+async function updateBrightness(event) {
+ event.preventDefault();
+ clearTimeout(brightnessTimeout);
+ brightnessTimeout = setTimeout(async function() {
+ const brightness = document.getElementById('brightness').value;
+ await post('/brightness', brightness);
+ }, 500);
+}
+
async function updateDelay(event) {
event.preventDefault();
clearTimeout(delayTimeout);
@@ -62,6 +80,14 @@ async function updateNumLeds(event) {
await post('/num_leds', numLeds);
}
+async function updateWifi(event) {
+ event.preventDefault();
+ const ssid = document.getElementById('ssid').value;
+ const password = document.getElementById('password').value;
+ console.log(ssid, password);
+ //await post('/num_leds', numLeds);
+}
+
function createPatternButtons(patterns) {
const container = document.getElementById('pattern_buttons');
container.innerHTML = ''; // Clear previous buttons
@@ -83,7 +109,11 @@ 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);
+ document.getElementById('brightness').addEventListener('input', updateBrightness);
+ document.getElementById('num_leds_form').addEventListener('submit', updateNumLeds);
+ document.getElementById('wifi_form').addEventListener('submit', updateWifi);
+ document.getElementById('delay').addEventListener('touchend', updateDelay);
+ document.getElementById('brightness').addEventListener('touchend', updateBrightness);
try {
const patterns = await get("/patterns");
@@ -92,4 +122,22 @@ document.addEventListener('DOMContentLoaded', async function() {
} catch (error) {
console.error('Error fetching patterns:', error);
}
+
+
});
+
+
+// Function to toggle the display of the settings menu
+function selectSettings() {
+ const settingsMenu = document.getElementById('settings_menu');
+ controls = document.getElementById('controls');
+ settingsMenu.style.display = 'block';
+ controls.style.display = 'none';
+}
+
+function selectControls() {
+ const settingsMenu = document.getElementById('settings_menu');
+ controls = document.getElementById('controls');
+ settingsMenu.style.display = 'none';
+ controls.style.display = 'block';
+}
diff --git a/main.py b/main.py
index 9e3b4f4..c5729b8 100644
--- a/main.py
+++ b/main.py
@@ -1,21 +1,24 @@
from machine import Pin
from patterns import Patterns
+from settings import Settings
import socket
import select
import json
-
+import utime
+import sys
+
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
+ self.settings = Settings()
+ print(self.settings)
+ self.patterns = Patterns(pin, num_leds)
+ self.patterns.select(self.settings["selected_pattern"])
+ self.patterns.set_color1(tuple(int(self.settings["color1"][i:i+2], 16) for i in (1, 5, 3)))
+ self.patterns.set_color2(tuple(int(self.settings["color2"][i:i+2], 16) for i in (1, 5, 3)))
# Initialize single LED
self.led = Pin(led_pin, Pin.OUT)
@@ -29,13 +32,7 @@ class LEDServer:
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.html = self.read_file("/index.html")
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()))
@@ -50,92 +47,88 @@ class LEDServer:
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:
+ paths = {
+ "/num_leds" : self.num_leds,
+ "/pattern": self.pattern,
+ "/delay": self.delay,
+ "/brightness": self.brightness,
+ "/color": self.color,
+ "/color2": self.color2
+ }
-# 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')
+ if path in paths:
+ paths[path](client_socket, post_data)
else:
client_socket.send(b'HTTP/1.0 404 Not Found\r\nContent-Type: text/plain\r\n\r\n')
+ def num_leds(self, client_socket, post_data):
+ try:
+ num_leds = int(post_data)
+ self.patterns.update_num_leds(4,num_leds)
+ self.settings["num_leds"] = num_leds
+ self.settings.save()
+ 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')
+
+ def pattern(self, client_socket, post_data):
+ if self.patterns.select(post_data):
+ self.settings["selected_pattern"] = post_data
+ self.settings.save()
+ client_socket.send(b'HTTP/1.0 200 OK\r\n\r\n')
+ else:
+ client_socket.send(b'HTTP/1.0 400 Bad request\r\n\r\n')
+
+ def delay(self, client_socket, post_data):
+ try:
+ delay = int(post_data)
+ self.patterns.set_delay(delay)
+ self.settings["delay"] = delay
+ self.settings.save()
+ 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')
+
+ def brightness(self, client_socket, post_data):
+ try:
+ brightness = int(post_data)
+ self.patterns.set_brightness(brightness)
+ self.settings["brightness"] = brightness
+ self.settings.save()
+ 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')
+
+ def color(self, client_socket, post_data):
+ try:
+ self.patterns.set_color1(tuple(int(post_data[i:i+2], 16) for i in (1, 5, 3))) # Convert hex to RGB
+ self.settings["color1"] = post_data
+ self.settings.save()
+ 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')
+
+ def color2(self, client_socket, post_data):
+ try:
+ self.patterns.set_color2(tuple(int(post_data[i:i+2], 16) for i in (1, 5, 3))) # Convert hex to RGB
+ self.settings["color2"] = post_data
+ self.settings.save()
+ 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')
+
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)
+ client_socket.send(self.html.format(
+ num_leds=self.settings["num_leds"],
+ delay=self.settings["delay"],
+ brightness=self.settings["brightness"],
+ color=self.settings["color1"],
+ color2=self.settings["color2"],
+ ssid=self.settings["wifi"]["ssid"]).encode())
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)
@@ -150,6 +143,8 @@ class LEDServer:
def start(self):
count = 0
+ average_time = 0
+ previous_time = utime.ticks_us()
try:
while True:
count += 1
@@ -169,17 +164,18 @@ class LEDServer:
if count > 50:
self.led.off()
+ #print(utime.ticks_us() - previous_time)
if count > 100:
self.led.on()
count = 0
-
+ # previous_time = utime.ticks_us()
self.patterns.tick()
except Exception as e:
print("Error:", e)
+ sys.print_exception(e)
finally:
self.server_socket.close()
- self.save_settings()
# Example of creating and starting the server
if __name__ == "__main__":
diff --git a/patterns.py b/patterns.py
index 7f7d55a..e399298 100644
--- a/patterns.py
+++ b/patterns.py
@@ -12,6 +12,8 @@ class Patterns:
self.delay = delay
self.brightness = brightness
self.patterns = {
+ "off": self.off,
+ "on" : self.on,
"color_wipe": self.color_wipe_step,
"rainbow_cycle": self.rainbow_cycle_step,
"theater_chase": self.theater_chase_step,
@@ -25,7 +27,7 @@ class Patterns:
self.selected = selected
self.color1 = color1
self.color2 = color2
- self.transition_duration = 5000 # Duration of color transition in milliseconds
+ self.transition_duration = 50 # Duration of color transition in milliseconds
self.transition_step = 0
def tick(self):
@@ -52,11 +54,30 @@ class Patterns:
def apply_brightness(self, color):
return tuple(int(c * self.brightness / 255) for c in color)
+ def select(self, pattern):
+ if pattern in self.patterns:
+ self.selected = pattern
+ return True
+ return False
+
def fill(self):
for i in range(self.num_leds):
self.n[i] = self.color1
self.n.write()
+ def off(self):
+ color = self.color1
+ self.color1 = (0,0,0)
+ self.fill()
+ self.color1 = color
+
+ def on(self):
+ color = self.color1
+ self.color1 = self.apply_brightness(self.color1)
+ self.fill()
+ self.color1 = color
+
+
def color_wipe_step(self):
color = self.apply_brightness(self.color1)
current_time = utime.ticks_ms()
@@ -64,7 +85,7 @@ class Patterns:
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] = color
+ self.n[self.pattern_step] = self.apply_brightness(color)
self.n.write()
self.pattern_step += 1
else:
@@ -96,7 +117,7 @@ class Patterns:
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
for i in range(self.num_leds):
if (i + self.pattern_step) % 3 == 0:
- self.n[i] = self.color1
+ self.n[i] = self.apply_brightness(self.color1)
else:
self.n[i] = (0, 0, 0)
self.n.write()
@@ -108,7 +129,7 @@ class Patterns:
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
if self.pattern_step % 2 == 0:
for i in range(self.num_leds):
- self.n[i] = self.color1
+ self.n[i] = self.apply_brightness(self.color1)
else:
for i in range(self.num_leds):
self.n[i] = (0, 0, 0)
@@ -209,11 +230,13 @@ if __name__ == "__main__":
p = Patterns(4, 180)
p.set_color1((255,0,0))
p.set_color2((0,255,0))
+ #p.set_delay(10)
try:
while True:
for key in p.patterns:
print(key)
- for _ in range(1000):
+ p.select(key)
+ for _ in range(2000):
p.tick()
utime.sleep_ms(1)
except KeyboardInterrupt: