change to hoop
This commit is contained in:
parent
a829310f45
commit
4b06aa0841
12
src/boot.py
12
src/boot.py
|
@ -11,9 +11,9 @@ password = settings.get('wifi', {}).get('password', None)
|
||||||
ip = settings.get('wifi', {}).get('ip', None)
|
ip = settings.get('wifi', {}).get('ip', None)
|
||||||
gateway = settings.get('wifi', {}).get('gateway', None)
|
gateway = settings.get('wifi', {}).get('gateway', None)
|
||||||
|
|
||||||
for i in range(10):
|
# for i in range(10):
|
||||||
config = wifi.connect(ssid, password, ip, gateway)
|
# config = wifi.connect(ssid, password, ip, gateway)
|
||||||
if config:
|
# if config:
|
||||||
print(config)
|
# print(config)
|
||||||
break
|
# break
|
||||||
time.sleep(0.1)
|
# time.sleep(0.1)
|
|
@ -0,0 +1,117 @@
|
||||||
|
from machine import Pin
|
||||||
|
from rp2 import PIO, StateMachine, asm_pio
|
||||||
|
from time import sleep
|
||||||
|
import array
|
||||||
|
import uctypes
|
||||||
|
from uctypes import BF_POS, BF_LEN, UINT32, BFUINT32, struct
|
||||||
|
|
||||||
|
PIO0_BASE = 0x50200000
|
||||||
|
PIO1_BASE = 0x50300000
|
||||||
|
DMA_BASE = 0x50000000
|
||||||
|
DMA_CHAN_WIDTH = 0x40
|
||||||
|
DMA_CHAN_COUNT = 12
|
||||||
|
|
||||||
|
DMA_SIZE_BYTE = 0x0
|
||||||
|
DMA_SIZE_HALFWORD = 0x1
|
||||||
|
DMA_SIZE_WORD = 0x2
|
||||||
|
|
||||||
|
# DMA: RP2040 datasheet 2.5.7
|
||||||
|
DMA_CTRL_TRIG_FIELDS = {
|
||||||
|
"AHB_ERROR": 31<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"READ_ERROR": 30<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"WRITE_ERROR": 29<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"BUSY": 24<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"SNIFF_EN": 23<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"BSWAP": 22<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"IRQ_QUIET": 21<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"TREQ_SEL": 15<<BF_POS | 6<<BF_LEN | BFUINT32,
|
||||||
|
"CHAIN_TO": 11<<BF_POS | 4<<BF_LEN | BFUINT32,
|
||||||
|
"RING_SEL": 10<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"RING_SIZE": 6<<BF_POS | 4<<BF_LEN | BFUINT32,
|
||||||
|
"INCR_WRITE": 5<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"INCR_READ": 4<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"DATA_SIZE": 2<<BF_POS | 2<<BF_LEN | BFUINT32,
|
||||||
|
"HIGH_PRIORITY":1<<BF_POS | 1<<BF_LEN | BFUINT32,
|
||||||
|
"EN": 0<<BF_POS | 1<<BF_LEN | BFUINT32
|
||||||
|
}
|
||||||
|
# Channel-specific DMA registers
|
||||||
|
DMA_CHAN_REGS = {
|
||||||
|
"READ_ADDR_REG": 0x00|UINT32,
|
||||||
|
"WRITE_ADDR_REG": 0x04|UINT32,
|
||||||
|
"TRANS_COUNT_REG": 0x08|UINT32,
|
||||||
|
"CTRL_TRIG_REG": 0x0c|UINT32,
|
||||||
|
"CTRL_TRIG": (0x0c,DMA_CTRL_TRIG_FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
# General DMA registers
|
||||||
|
DMA_REGS = {
|
||||||
|
"INTR": 0x400|UINT32,
|
||||||
|
"INTE0": 0x404|UINT32,
|
||||||
|
"INTF0": 0x408|UINT32,
|
||||||
|
"INTS0": 0x40c|UINT32,
|
||||||
|
"INTE1": 0x414|UINT32,
|
||||||
|
"INTF1": 0x418|UINT32,
|
||||||
|
"INTS1": 0x41c|UINT32,
|
||||||
|
"TIMER0": 0x420|UINT32,
|
||||||
|
"TIMER1": 0x424|UINT32,
|
||||||
|
"TIMER2": 0x428|UINT32,
|
||||||
|
"TIMER3": 0x42c|UINT32,
|
||||||
|
"MULTI_CHAN_TRIGGER": 0x430|UINT32,
|
||||||
|
"SNIFF_CTRL": 0x434|UINT32,
|
||||||
|
"SNIFF_DATA": 0x438|UINT32,
|
||||||
|
"FIFO_LEVELS": 0x440|UINT32,
|
||||||
|
"CHAN_ABORT": 0x444|UINT32
|
||||||
|
}
|
||||||
|
|
||||||
|
DMA_CHANS = [struct(DMA_BASE + n*DMA_CHAN_WIDTH, DMA_CHAN_REGS) for n in range(0,DMA_CHAN_COUNT)]
|
||||||
|
DMA_DEVICE = struct(DMA_BASE, DMA_REGS)
|
||||||
|
|
||||||
|
DMA_CH0_AL3_TRANS_COUNT = DMA_BASE + 0x38
|
||||||
|
|
||||||
|
class PIO_DMA_Transfer():
|
||||||
|
def __init__(self, dma_channel, sm_num, block_size, transfer_count):
|
||||||
|
self.dma_chan = DMA_CHANS[dma_channel]
|
||||||
|
self.channel_number = dma_channel
|
||||||
|
|
||||||
|
if (sm_num >= 0 and sm_num < 4):
|
||||||
|
self.dma_chan.WRITE_ADDR_REG = PIO0_BASE + 0x10 + sm_num *4
|
||||||
|
self.dma_chan.CTRL_TRIG.TREQ_SEL = sm_num
|
||||||
|
elif (sm_num < 8):
|
||||||
|
self.dma_chan.WRITE_ADDR_REG = PIO1_BASE + 0x10 + (sm_num-4) *4
|
||||||
|
self.dma_chan.CTRL_TRIG.TREQ_SEL = sm_num + 4
|
||||||
|
|
||||||
|
if (block_size == 8):
|
||||||
|
self.dma_chan.CTRL_TRIG.DATA_SIZE = DMA_SIZE_BYTE
|
||||||
|
if (block_size == 16):
|
||||||
|
self.dma_chan.CTRL_TRIG.DATA_SIZE = DMA_SIZE_HALFWORD
|
||||||
|
if (block_size == 32):
|
||||||
|
self.dma_chan.CTRL_TRIG.DATA_SIZE = DMA_SIZE_WORD
|
||||||
|
|
||||||
|
self.dma_chan.TRANS_COUNT_REG = transfer_count
|
||||||
|
|
||||||
|
#Do I just always want these?
|
||||||
|
self.dma_chan.CTRL_TRIG.INCR_WRITE = 0
|
||||||
|
self.dma_chan.CTRL_TRIG.INCR_READ = 1
|
||||||
|
|
||||||
|
def start_transfer(self, buffer):
|
||||||
|
self.dma_chan.READ_ADDR_REG = uctypes.addressof(buffer)
|
||||||
|
self.dma_chan.CTRL_TRIG.EN = 1
|
||||||
|
|
||||||
|
def transfer_count(self):
|
||||||
|
return self.dma_chan.TRANS_COUNT_REG
|
||||||
|
|
||||||
|
def busy(self):
|
||||||
|
if self.dma_chan.CTRL_TRIG.DATA_SIZE == 1:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
80
src/main.py
80
src/main.py
|
@ -1,54 +1,34 @@
|
||||||
import asyncio
|
|
||||||
from settings import Settings
|
from time import sleep
|
||||||
from web import web
|
from neopixel import NeoPixel
|
||||||
|
from machine import UART, Pin, PWM, ADC
|
||||||
|
import _thread
|
||||||
|
import network
|
||||||
|
import espnow
|
||||||
|
|
||||||
from patterns import Patterns
|
from patterns import Patterns
|
||||||
import gc
|
|
||||||
import utime
|
adc = ADC(2, atten=ADC.ATTN_11DB)
|
||||||
import machine
|
sta = network.WLAN(network.WLAN.IF_STA) # Or network.WLAN.IF_AP
|
||||||
import ntptime
|
sta.active(True)
|
||||||
import time
|
|
||||||
import wifi
|
e = espnow.ESPNow()
|
||||||
|
e.active(True)
|
||||||
|
|
||||||
|
#e.add_peer(broadcast)
|
||||||
|
|
||||||
|
p = Patterns()
|
||||||
|
|
||||||
|
_thread.start_new_thread(p.scan_single_led, ((255,0,0),0))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
value = adc.read_uv()*2
|
||||||
|
if value < 3_500_000:
|
||||||
|
p.run = False
|
||||||
|
p.off()
|
||||||
|
print(f"Voltage {value}")
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
|
||||||
|
|
||||||
patterns = Patterns(4, settings["num_leds"], selected=settings["selected_pattern"])
|
|
||||||
patterns.set_color1(tuple(int(settings["color1"][i:i+2], 16) for i in (1, 5, 3)))
|
|
||||||
patterns.set_color2(tuple(int(settings["color2"][i:i+2], 16) for i in (1, 5, 3)))
|
|
||||||
patterns.set_brightness(int(settings["brightness"]))
|
|
||||||
patterns.set_delay(int(settings["delay"]))
|
|
||||||
|
|
||||||
w = web(settings, patterns)
|
|
||||||
print(settings)
|
|
||||||
# start the server in a bacakground task
|
|
||||||
print("Starting")
|
|
||||||
server = asyncio.create_task(w.start_server(host="0.0.0.0", port=80))
|
|
||||||
wdt = machine.WDT(timeout=10000)
|
|
||||||
|
|
||||||
async def tick():
|
|
||||||
while True:
|
|
||||||
patterns.tick()
|
|
||||||
await asyncio.sleep_ms(1)
|
|
||||||
|
|
||||||
asyncio.create_task(tick())
|
|
||||||
|
|
||||||
first = True
|
|
||||||
|
|
||||||
while True:
|
|
||||||
#print(time.localtime())
|
|
||||||
|
|
||||||
# gc.collect()
|
|
||||||
for i in range(60):
|
|
||||||
wdt.feed()
|
|
||||||
await asyncio.sleep_ms(500)
|
|
||||||
|
|
||||||
# cleanup before ending the application
|
|
||||||
await server
|
|
||||||
|
|
||||||
asyncio.run(main())
|
|
||||||
|
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
361
src/patterns.py
361
src/patterns.py
|
@ -4,289 +4,92 @@ import utime
|
||||||
import random
|
import random
|
||||||
|
|
||||||
class Patterns:
|
class Patterns:
|
||||||
def __init__(self, pin, num_leds, color1=(0,0,0), color2=(0,0,0), brightness=127, selected="rainbow_cycle", delay=100):
|
def __init__(self):
|
||||||
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
|
self.pin_data = (21, 277) # Example: Pin 21, 277 LEDs
|
||||||
self.num_leds = num_leds
|
self.strip = NeoPixel(Pin(self.pin_data[0]), self.pin_data[1])
|
||||||
self.pattern_step = 0
|
self.run = False
|
||||||
self.last_update = utime.ticks_ms()
|
|
||||||
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,
|
|
||||||
"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,
|
|
||||||
"2 step forward 1 step back": self.two_steps_forward_one_step_back_step,
|
|
||||||
"external": None
|
|
||||||
}
|
|
||||||
self.selected = selected
|
|
||||||
self.color1 = color1
|
|
||||||
self.color2 = color2
|
|
||||||
self.transition_duration = 50 # Duration of color transition in milliseconds
|
|
||||||
self.transition_step = 0
|
|
||||||
|
|
||||||
def sync(self):
|
|
||||||
self.pattern_step=0
|
|
||||||
self.last_update = utime.ticks_ms()
|
|
||||||
|
|
||||||
def tick(self):
|
self.strip.fill((0,0,0))
|
||||||
if self.patterns[self.selected]:
|
self.strip.write()
|
||||||
self.patterns[self.selected]()
|
print(f"Initialized single strip on Pin {self.pin_data[0]} with {self.pin_data[1]} LEDs.")
|
||||||
|
|
||||||
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):
|
def scan_single_led(self, color=(255, 255, 255), delay_ms=0):
|
||||||
self.brightness = brightness
|
"""
|
||||||
|
Scans a single LED along the length of the strip, turning it on and then off
|
||||||
def set_color1(self, color):
|
as it moves. Optimized for speed by batching writes.
|
||||||
print(color)
|
|
||||||
self.color1 = self.apply_brightness(color)
|
Args:
|
||||||
|
color (tuple): The (R, G, B) color of the scanning LED.
|
||||||
def set_color2(self, color):
|
delay_ms (int): Optional extra delay in milliseconds between each LED position.
|
||||||
self.color2 = self.apply_brightness(color)
|
Set to 0 for fastest possible without *extra* delay.
|
||||||
|
"""
|
||||||
def apply_brightness(self, color):
|
self.run = True
|
||||||
return tuple(int(c * self.brightness / 255) for c in color)
|
num_pixels = len(self.strip)
|
||||||
|
last_pixel_index = num_pixels - 1
|
||||||
def select(self, pattern):
|
|
||||||
if pattern in self.patterns:
|
# Turn off all pixels initially for a clean start if not already off
|
||||||
self.selected = pattern
|
self.strip.fill((0, 0, 0))
|
||||||
return True
|
# No write here yet, as the first pixel will be set immediately
|
||||||
return False
|
|
||||||
|
while self.run:
|
||||||
def set(self, i, color):
|
# --- Scan Forward ---
|
||||||
self.n[i] = color
|
for i in range(num_pixels):
|
||||||
|
if not self.run:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Turn on the current pixel
|
||||||
|
self.strip[i] = color
|
||||||
|
|
||||||
|
# Turn off the previous pixel if not the first one
|
||||||
|
if i > 0:
|
||||||
|
self.strip[i - 1] = (0, 0, 0)
|
||||||
|
# If it's the first pixel, ensure the last one from previous cycle is off (if applicable)
|
||||||
|
elif i == 0 and num_pixels > 1: # Only relevant if scanning backwards too
|
||||||
|
self.strip[last_pixel_index] = (0,0,0)
|
||||||
|
|
||||||
|
|
||||||
|
self.strip.write() # Write changes to the strip
|
||||||
|
if delay_ms > 0:
|
||||||
|
utime.sleep_ms(delay_ms)
|
||||||
|
|
||||||
|
# Ensure the last pixel of the forward scan is turned off
|
||||||
|
if self.run and num_pixels > 0:
|
||||||
|
self.strip[last_pixel_index] = (0, 0, 0)
|
||||||
|
self.strip.write() # Write this final change
|
||||||
|
|
||||||
|
|
||||||
|
# --- Scan Backward (optional, remove this loop if you only want forward) ---
|
||||||
|
for i in range(num_pixels - 1, -1, -1): # From last_pixel_index down to 0
|
||||||
|
if not self.run:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Turn on the current pixel
|
||||||
|
self.strip[i] = color
|
||||||
|
|
||||||
|
# Turn off the next pixel (which was the previous one in reverse scan)
|
||||||
|
if i < last_pixel_index:
|
||||||
|
self.strip[i + 1] = (0, 0, 0)
|
||||||
|
# If it's the last pixel of the reverse scan, ensure the first one from previous cycle is off (if applicable)
|
||||||
|
elif i == last_pixel_index and num_pixels > 1: # Only relevant if scanning forward too
|
||||||
|
self.strip[0] = (0,0,0)
|
||||||
|
|
||||||
|
self.strip.write() # Write changes to the strip
|
||||||
|
if delay_ms > 0:
|
||||||
|
utime.sleep_ms(delay_ms)
|
||||||
|
|
||||||
|
# Ensure the first pixel of the backward scan is turned off
|
||||||
|
if self.run and num_pixels > 0:
|
||||||
|
self.strip[0] = (0, 0, 0)
|
||||||
|
self.strip.write() # Write this final change
|
||||||
|
|
||||||
def write(self):
|
|
||||||
self.n.write()
|
|
||||||
|
|
||||||
def fill(self):
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
self.n[i] = self.color1
|
|
||||||
self.n.write()
|
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
color = self.color1
|
print("Turning off LEDs.")
|
||||||
self.color1 = (0,0,0)
|
self.run = False
|
||||||
self.fill()
|
self.strip.fill((0,0,0))
|
||||||
self.color1 = color
|
self.strip.write()
|
||||||
|
utime.sleep_ms(50)
|
||||||
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()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
|
||||||
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 rainbow_cycle_step(self):
|
# Example Usage (for MicroPython on actual hardware):
|
||||||
current_time = utime.ticks_ms()
|
# (Same as before, just removed from the main block for brevity)
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay/5:
|
|
||||||
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)
|
|
||||||
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
rc_index = (i * 256 // self.num_leds) + self.pattern_step
|
|
||||||
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 theater_chase_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
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.apply_brightness(self.color1)
|
|
||||||
else:
|
|
||||||
self.n[i] = (0, 0, 0)
|
|
||||||
self.n.write()
|
|
||||||
self.pattern_step = (self.pattern_step + 1) % 3
|
|
||||||
self.last_update = current_time
|
|
||||||
|
|
||||||
def blink_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
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.apply_brightness(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)
|
|
||||||
)
|
|
||||||
|
|
||||||
def two_steps_forward_one_step_back_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
|
||||||
# Move forward 2 steps and backward 1 step
|
|
||||||
if self.direction == 1: # Moving forward
|
|
||||||
if self.scanner_position < self.num_leds - 2:
|
|
||||||
self.scanner_position += 2 # Move forward 2 steps
|
|
||||||
else:
|
|
||||||
self.direction = -1 # Change direction to backward
|
|
||||||
else: # Moving backward
|
|
||||||
if self.scanner_position > 0:
|
|
||||||
self.scanner_position -= 1 # Move backward 1 step
|
|
||||||
else:
|
|
||||||
self.direction = 1 # Change direction to forward
|
|
||||||
|
|
||||||
# Set all LEDs to off
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
self.n[i] = (0, 0, 0)
|
|
||||||
|
|
||||||
# Set the current position to the color
|
|
||||||
self.n[self.scanner_position] = self.apply_brightness(self.color1)
|
|
||||||
|
|
||||||
# Apply the color transition
|
|
||||||
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)
|
|
||||||
self.n[self.scanner_position] = 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
|
|
||||||
|
|
||||||
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)
|
|
||||||
p.select(key)
|
|
||||||
for _ in range(2000):
|
|
||||||
p.tick()
|
|
||||||
utime.sleep_ms(1)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
p.fill((0, 0, 0))
|
|
||||||
|
|
|
@ -37,35 +37,5 @@
|
||||||
<input type="color" id="color2" name="color2" value="{{settings['color2']}}">
|
<input type="color" id="color2" name="color2" value="{{settings['color2']}}">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Settings Menu for num_leds, Wi-Fi SSID, and Password -->
|
|
||||||
|
|
||||||
<div id="settings_menu" style="display: none;">
|
|
||||||
<h2>Settings</h2>
|
|
||||||
|
|
||||||
<!-- Separate form for submitting num_leds -->
|
|
||||||
<form id="num_leds_form" method="post" action="/num_leds">
|
|
||||||
<label for="num_leds">Number of LEDs:</label>
|
|
||||||
<input type="text" id="num_leds" name="num_leds" value="{{settings['num_leds']}}">
|
|
||||||
<input type="submit" value="Update Number of LEDs">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Form for Wi-Fi SSID and password -->
|
|
||||||
<form id="wifi_form" method="post" action="/wifi_settings">
|
|
||||||
<label for="ssid">Wi-Fi SSID:</label>
|
|
||||||
<input type="text" id="ssid" name="ssid" value="{{settings['wifi']['ssid']}}">
|
|
||||||
<br>
|
|
||||||
<label for="password">Wi-Fi Password:</label>
|
|
||||||
<input type="password" id="password" name="password">
|
|
||||||
<br>
|
|
||||||
<label for="ip">Wi-Fi IP:</label>
|
|
||||||
<input type="ip" id="ip" name="ip" value="{{settings.get('wifi', {}).get('ip', '')}}">
|
|
||||||
<br>
|
|
||||||
<label for="gateway">Wi-Fi Gateway:</label>
|
|
||||||
<input type="gateway" id="gateway" name="gateway" value="{{settings.get('wifi', {}).get('gateway', '')}}">
|
|
||||||
<br>
|
|
||||||
<input type="submit" value="Save Wi-Fi Settings">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
46
src/web.py
46
src/web.py
|
@ -5,7 +5,7 @@ from microdot.websocket import with_websocket
|
||||||
import json
|
import json
|
||||||
import wifi
|
import wifi
|
||||||
|
|
||||||
def web(settings, patterns):
|
def web(settings, patterns, patterns2):
|
||||||
app = Microdot()
|
app = Microdot()
|
||||||
Response.default_content_type = 'text/html'
|
Response.default_content_type = 'text/html'
|
||||||
|
|
||||||
|
@ -20,24 +20,13 @@ def web(settings, patterns):
|
||||||
return 'Not found', 404
|
return 'Not found', 404
|
||||||
return send_file('static/' + path)
|
return send_file('static/' + path)
|
||||||
|
|
||||||
@app.post("/num_leds")
|
|
||||||
def num_leds(request):
|
|
||||||
try:
|
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
|
||||||
num_leds = int(data["num_leds"])
|
|
||||||
patterns.update_num_leds(4, num_leds)
|
|
||||||
settings["num_leds"] = num_leds
|
|
||||||
settings.save()
|
|
||||||
return "OK", 200
|
|
||||||
except (ValueError, KeyError, json.JSONDecodeError):
|
|
||||||
return "Bad request", 400
|
|
||||||
|
|
||||||
@app.post("/pattern")
|
@app.post("/pattern")
|
||||||
def pattern(request):
|
def pattern(request):
|
||||||
try:
|
try:
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
pattern = data["pattern"]
|
pattern = data["pattern"]
|
||||||
if patterns.select(pattern):
|
if patterns.select(pattern):
|
||||||
|
patterns2.select(pattern)
|
||||||
settings["selected_pattern"] = pattern
|
settings["selected_pattern"] = pattern
|
||||||
settings.save()
|
settings.save()
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
|
@ -52,6 +41,7 @@ def web(settings, patterns):
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
delay = int(data["delay"])
|
delay = int(data["delay"])
|
||||||
patterns.set_delay(delay)
|
patterns.set_delay(delay)
|
||||||
|
patterns2.set_delay(delay)
|
||||||
settings["delay"] = delay
|
settings["delay"] = delay
|
||||||
settings.save()
|
settings.save()
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
|
@ -64,6 +54,7 @@ def web(settings, patterns):
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
brightness = int(data["brightness"])
|
brightness = int(data["brightness"])
|
||||||
patterns.set_brightness(brightness)
|
patterns.set_brightness(brightness)
|
||||||
|
patterns2.set_brightness(brightness)
|
||||||
settings["brightness"] = brightness
|
settings["brightness"] = brightness
|
||||||
settings.save()
|
settings.save()
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
|
@ -76,6 +67,7 @@ def web(settings, patterns):
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
color = data["color"]
|
color = data["color"]
|
||||||
patterns.set_color1(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
patterns.set_color1(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
|
patterns2.set_color1(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
settings["color1"] = color
|
settings["color1"] = color
|
||||||
settings.save()
|
settings.save()
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
|
@ -88,39 +80,13 @@ def web(settings, patterns):
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
color = data["color2"]
|
color = data["color2"]
|
||||||
patterns.set_color2(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
patterns.set_color2(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
|
patterns2.set_color2(tuple(int(color[i:i+2], 16) for i in (1, 3, 5))) # Convert hex to RGB
|
||||||
settings["color2"] = color
|
settings["color2"] = color
|
||||||
settings.save()
|
settings.save()
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
except (KeyError, json.JSONDecodeError, ValueError):
|
except (KeyError, json.JSONDecodeError, ValueError):
|
||||||
return "Bad request", 400
|
return "Bad request", 400
|
||||||
|
|
||||||
|
|
||||||
@app.post("/wifi_settings")
|
|
||||||
def wifi_settings(request):
|
|
||||||
try:
|
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
|
||||||
print(data)
|
|
||||||
ssid = settings['wifi']['ssid'] = data['ssid']
|
|
||||||
password = settings['wifi']['password'] = data.get('password', settings['wifi']['password'])
|
|
||||||
ip = settings['wifi']['ip'] = data.get('ip', None)
|
|
||||||
gateway = settings['wifi']['gateway'] = data.get('gateway', None)
|
|
||||||
print(settings)
|
|
||||||
|
|
||||||
if config := wifi.connect(ssid, password, ip, gateway):
|
|
||||||
print(config)
|
|
||||||
settings.save()
|
|
||||||
|
|
||||||
return "OK", 200
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Wifi {e}")
|
|
||||||
return "Bad request", 400
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/sync")
|
|
||||||
def sync(request):
|
|
||||||
patterns.sync()
|
|
||||||
return "OK", 200
|
|
||||||
|
|
||||||
@app.route("/external")
|
@app.route("/external")
|
||||||
@with_websocket
|
@with_websocket
|
||||||
async def ws(request, ws):
|
async def ws(request, ws):
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
import array, time
|
||||||
|
from machine import Pin
|
||||||
|
import rp2
|
||||||
|
from time import sleep
|
||||||
|
import dma
|
||||||
|
|
||||||
|
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=8)
|
||||||
|
def ws2812():
|
||||||
|
T1 = 2
|
||||||
|
T2 = 5
|
||||||
|
T3 = 3
|
||||||
|
wrap_target()
|
||||||
|
label("bitloop")
|
||||||
|
out(x, 1) .side(0) [T3 - 1]
|
||||||
|
jmp(not_x, "do_zero") .side(1) [T1 - 1]
|
||||||
|
jmp("bitloop") .side(1) [T2 - 1]
|
||||||
|
label("do_zero")
|
||||||
|
nop() .side(0) [T2 - 1]
|
||||||
|
wrap()
|
||||||
|
|
||||||
|
class WS2812B:
|
||||||
|
def __init__(self, num_leds, pin, state_machine, brightness=0.1, invert=False):
|
||||||
|
self.sm = rp2.StateMachine(state_machine, ws2812, freq=8_000_000, sideset_base=Pin(pin))
|
||||||
|
self.sm.active(1)
|
||||||
|
self.ar = bytearray(num_leds*3)
|
||||||
|
self.num_leds = num_leds
|
||||||
|
self.brightness = brightness
|
||||||
|
self.invert = invert
|
||||||
|
self.pio_dma = dma.PIO_DMA_Transfer(state_machine+4, state_machine, 8, num_leds*3)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
self.pio_dma.start_transfer(self.ar)
|
||||||
|
|
||||||
|
def set(self, i, color):
|
||||||
|
self.ar[i*3] = int(color[1]*self.brightness)
|
||||||
|
self.ar[i*3+1] = int(color[0]*self.brightness)
|
||||||
|
self.ar[i*3+2] = int(color[2]*self.brightness)
|
||||||
|
|
||||||
|
def fill(self, color):
|
||||||
|
for i in range(self.num_leds):
|
||||||
|
self.set(i, color)
|
||||||
|
|
||||||
|
def busy(self):
|
||||||
|
return self.pio_dma.busy()
|
||||||
|
|
||||||
|
BLACK = (0, 0, 0)
|
||||||
|
RED = (255, 0, 0)
|
||||||
|
YELLOW = (255, 150, 0)
|
||||||
|
GREEN = (0, 255, 0)
|
||||||
|
CYAN = (0, 255, 255)
|
||||||
|
BLUE = (0, 0, 255)
|
||||||
|
PURPLE = (180, 0, 255)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
COLORS = (BLACK, RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
num_leds, pin, sm, brightness = 10, 0, 0, 1
|
||||||
|
ws0 = WS2812B(num_leds, pin, sm, brightness)
|
||||||
|
while True:
|
||||||
|
for color in ws0.COLORS:
|
||||||
|
ws0.fill(color)
|
||||||
|
ws0.show()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue