diff --git a/uPixels/uPixels.css b/uPixels/uPixels.css index c1e5a75..915197f 100644 --- a/uPixels/uPixels.css +++ b/uPixels/uPixels.css @@ -20,16 +20,36 @@ nav i { border-radius: 10px; } -.controls .colorpicker .random-color { +.controls h5 { + margin: 5px 0 0 0 !important; +} + +.controls .colorpicker form { + text-align: left; +} + +.controls .colorpicker .random-color, .default-delay { margin: 0 !important; } -.controls .colorpicker .random-color span { +.controls .colorpicker .random-color span , .default-delay span { padding-left: 26px !important; color: black; margin-top: -4px; } +.controls .settings .clear { + height: 30px; + width: 120px; + margin-top: 10px; + padding: 0; +} + +.controls .settings .clear i { + margin-right: 2px; + margin-left: 5px; +} + .tabs i { margin-right: 5px; vertical-align: middle; @@ -86,10 +106,11 @@ nav i { .tabs-content.carousel.carousel-slider { height: 600px !important; + overflow: auto; } .rainbow input.iterations, .segment-length .segment-select { - width: 16px !important; + width: 34px !important; height: 50px !important; font-size: 30px !important; } @@ -105,5 +126,5 @@ nav i { .segment-length { text-align: center; margin: auto; - width: 170px; + width: 190px; } diff --git a/uPixels/uPixels.html b/uPixels/uPixels.html index 0d30efa..9b055ae 100644 --- a/uPixels/uPixels.html +++ b/uPixels/uPixels.html @@ -20,6 +20,7 @@ + @@ -43,6 +44,12 @@
Color Picker:
Random Color

+

+ +

@@ -54,6 +61,7 @@
Brightness: 50%
Delay: 10 ms
+ clearclear strip @@ -73,27 +81,13 @@
Delay: 10 ms
remove add
- play_arrow + play_arrow
  • call_missedBounce
    -
    -

    - -

    -

    - -

    -
    - play_arrow + play_arrow
  • @@ -103,7 +97,7 @@
    Delay: 10 ms

    @@ -114,13 +108,13 @@
    Delay: 10 ms

    - play_arrow + play_arrow
  • tollRGB Fade
    - play_arrow + play_arrow
  • @@ -128,31 +122,31 @@
    Delay: 10 ms
    Select Second Color:

    - play_arrow + play_arrow
  • -
  • +
  • blur_onRandom Fill
    - play_arrow + play_arrow
  • -
  • +
  • codeFill from Middle
    - play_arrow + play_arrow
  • -
  • +
  • compare_arrowsFill from Sides
    - play_arrow + play_arrow
  • -
  • +
  • fast_forwardFill Strip
    - play_arrow + play_arrow
  • @@ -165,12 +159,12 @@
    Starting Position: 1
    Segment Length:
    - remove - + remove + add
    -
    -
    - play_arrow +
    + play_arrow +
    @@ -179,15 +173,27 @@

    info_outlineAbout Device Name: - asdf + {{name}} + + + uPixels Version: + {{upixels_ver}} + + + MicroPython Version: + {{mp_ver}} IP Address: - asdf + {{ip}} + + + App Hosted at: + {{host}} Number of LEDS: - asdf + {{num}} diff --git a/uPixels/uPixels.js b/uPixels/uPixels.js index 83c331b..8fd3c18 100644 --- a/uPixels/uPixels.js +++ b/uPixels/uPixels.js @@ -1,13 +1,10 @@ var brightnessSlider, delaySlider, startingPositionSlider, segmentLengthSlider -$(document).ready(function(){ +$(document).ready(function() { $("#colorpicker").spectrum({ color: "rgb(0, 255, 155)", preferredFormat: 'rgb', showButtons: false, - showInput: true, - change: function(color) { - console.log($(this).spectrum('get').toRgb()); - } + showInput: true }); $("#second-colorpicker").spectrum({ color: "rgb(0, 171, 255)", @@ -21,89 +18,211 @@ $(document).ready(function(){ }); M.AutoInit(); - $('.tabs').tabs({'swipeable':true}); + $('.tabs').tabs({ + 'swipeable': true + }); delaySlider = document.getElementById('delay-slider'); noUiSlider.create(delaySlider, { - start: 10, - step: 1, - behavior: 'drag-tap', - range: { - 'min': 10, - 'max': 1000 - }, - format: wNumb({ - decimals: 0 - }) + start: 10, + step: 1, + behavior: 'drag-tap', + range: { + 'min': 10, + 'max': 1000 + }, + format: wNumb({ + decimals: 0 + }) }); - delaySlider.noUiSlider.on('update', function (delay) { + delaySlider.noUiSlider.on('update', function(delay) { $('#delay-label').text(delay); }) brightnessSlider = document.getElementById('brightness-slider'); noUiSlider.create(brightnessSlider, { - start: 50, - step: 1, - behavior: 'drag-tap', - range: { - 'min': 0, - 'max': 100 - }, - format: wNumb({ - decimals: 0 - }) + start: 100, + step: 1, + behavior: 'drag-tap', + range: { + 'min': 0, + 'max': 100 + }, + format: wNumb({ + decimals: 0 + }) }); - brightnessSlider.noUiSlider.on('update', function (brightness) { + brightnessSlider.noUiSlider.on('update', function(brightness) { $('#brightness-label').text(brightness); }) startingPositionSlider = document.getElementById('starting-position-slider'); noUiSlider.create(startingPositionSlider, { - start: 1, - step: 1, - behavior: 'drag-tap', - range: { - 'min': [0], - 'max': [300] - }, - format: wNumb({ - decimals: 0 - }) + start: 1, + step: 1, + behavior: 'drag-tap', + range: { + 'min': [0], + 'max': [300] + }, + format: wNumb({ + decimals: 0 + }) }); - startingPositionSlider.noUiSlider.on('update', function (position) { + startingPositionSlider.noUiSlider.on('update', function(position) { $('#position-label').text(position); }) - - // segmentLengthSlider = document.getElementById('segment-length-slider'); - // noUiSlider.create(segmentLengthSlider, { - // start: 50, - // step: 1, - // behavior: 'drag-tap', - // range: { - // 'min': [1], - // 'max': [300] - // }, - // format: wNumb({ - // decimals: 0 - // }) - // }); - - }); function changeVal(element, val) { - $(element).val(+$(element).val()+val); + $(element).val(+$(element).val() + val); } function togglePickers() { if ($("#random-color-checkbox").prop('checked')) { $("#colorpicker").spectrum("disable"); $("#second-colorpicker").spectrum("disable"); + document.getElementById('brightness-slider').setAttribute('disabled', true); } else { $("#colorpicker").spectrum("enable"); $("#second-colorpicker").spectrum("enable"); + document.getElementById('brightness-slider').removeAttribute('disabled'); + } +} + +function toggleDelaySlider() { + if ($("#default-delay-checkbox").prop('checked')) { + document.getElementById('delay-slider').setAttribute('disabled', true); + } else { + document.getElementById('delay-slider').removeAttribute('disabled'); + } +} + + +function getFirstColor() { + return $("#colorpicker").spectrum("get").toRgb(); +} + +function getBrightness() { + return document.getElementById('brightness-slider').noUiSlider.get() / 100; +} + +function getColorSelection() { + brightness = getBrightness() + if ($('#random-color-checkbox').is(":checked")) { + return null + } else { + color = getFirstColor() + } + return { + 'r': Math.round(color['r'] * brightness), + 'g': Math.round(color['g'] * brightness), + 'b': Math.round(color['b'] * brightness) + } +} + +function getDelaySelection() { + if ($('#default-delay-checkbox').is(":checked")) { + return undefined + } else { + return document.getElementById('delay-slider').noUiSlider.get() + } +} + +function execute(action, params = {}) { + var xhr = new XMLHttpRequest(); + xhr.open("POST", '/execute', true); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(JSON.stringify({'action': action, 'params': params})); +} + +function rainbow() { + execute('rainbow', { + 'ms': getDelaySelection(), + 'iterations': Number($('.rainbow .iterations').val()) + }) +} + +function bounce() { + execute('bounce', { + 'ms': getDelaySelection(), + 'color': getColorSelection() + }) +} + +function chase() { + if ($('.chase #left').is(":checked")) { + direction = 'left' + } else { + direction = 'right' + } + execute('chase', { + 'ms': getDelaySelection(), + 'color': getColorSelection(), + 'direction': direction + }) +} + +function rgbFade() { + execute('rgbFade', { + 'ms': getDelaySelection() + }) +} + +function altColors() { + if ($('#random-color-checkbox').is(":checked")) { + secondColor = false + } else { + secondColor = $("#second-colorpicker").spectrum("get").toRgb() } + execute('altColors', { + 'ms': getDelaySelection(), + 'firstColor': getColorSelection(), + 'secondColor': secondColor + }) +} + +function randomFill() { + execute('randomFill', { + 'ms': getDelaySelection(), + 'color': getColorSelection() + }) +} + +function fillFromMiddle() { + color + execute('fillFromMiddle', { + 'ms': getDelaySelection(), + 'color': getColorSelection() + }) +} + +function fillFromSides() { + execute('fillFromSides', { + 'ms': getDelaySelection(), + 'color': getColorSelection() + }) +} + +function fillStrip() { + execute('fillStrip', { + 'ms': getDelaySelection(), + 'color': getColorSelection() + }) +} + +function setSegment() { + clearStrip(); + start = Number(document.getElementById('starting-position-slider').noUiSlider.get()) + execute('setSegment', { + "segment_of_leds": Array.from(new Array(Number($(".segment-select").val())), (x, i) => i + start), + "color": getColorSelection() + }) +} + +function clearStrip() { + execute('clear') } diff --git a/uPixels/uPixels.py b/uPixels/uPixels.py index 2dca375..dd26042 100644 --- a/uPixels/uPixels.py +++ b/uPixels/uPixels.py @@ -1,26 +1,71 @@ -import machine, neopixel, time, urandom +import machine, uos, network, neopixel, time, urandom from uWeb import uWeb, loadJSON class uPixels: + VERSION = '1.0' def __init__(self, pin, num_leds, address="0.0.0.0", port=8000): + self.device_name = uos.uname()[0] self.pin = machine.Pin(pin, machine.Pin.OUT) # configure pin for leds self.np = neopixel.NeoPixel(self.pin, num_leds) # configure neopixel library self.address = address self.port = port + self.animation_map = { + 'rainbow': self.rainbow, + 'bounce': self.bounce, + 'chase': self.chase, + 'rgbFade': self.rgbFade, + 'altColors': self.altColors, + 'randomFill': self.randomFill, + 'fillFromMiddle': self.fillFromMiddle, + 'fillFromSides': self.fillFromSides, + 'fillStrip': self.fillStrip, + 'setSegment': self.setSegment, + 'clear': self.clear + } + + def setDeviceName(self, name): + self.device_name = name # web server methods def startServer(self): self.server = uWeb(self.address, self.port) self.server.routes({ - (uWeb.GET, "/"): self.app + (uWeb.GET, "/"): self.app, + (uWeb.POST, '/execute'): self.execute }) self.server.start() def app(self): - self.server.render('uPixels.html') + vars = { + 'name' : self.device_name, + 'upixels_ver': self.VERSION, + 'mp_ver': uos.uname()[3], + 'ip': network.WLAN(network.STA_IF).ifconfig()[0], + 'host': network.WLAN(network.STA_IF).ifconfig()[0]+":"+str(self.server.port), + 'num': self.np.n + } + self.server.render('uPixels.html', variables=vars) + + def execute(self): + query = loadJSON(self.server.request_body) + action = query["action"] + params = query["params"] + if 'color' in params.keys(): + if params['color'] != None: + params['color'] = (params['color']['r'], params['color']['g'], params['color']['b']) + if 'firstColor' in params.keys(): + if params['firstColor'] != None: + params['firstColor'] = (params['firstColor']['r'], params['firstColor']['g'], params['firstColor']['b']) + if 'secondColor' in params.keys(): + if params['secondColor'] != None: + params['secondColor'] = (params['secondColor']['r'], params['secondColor']['g'], params['secondColor']['b']) + print("passing ", params) + self.animation_map[action](**params) # call the animcation method # animation methods - def chase(self, ms=20, color=randColor(), direction='right'): + def chase(self, ms=20, color=None, direction='right'): + if color == None: + color = self.randColor() if direction == 'right': led_iter = range(self.np.n) else: @@ -31,7 +76,9 @@ def chase(self, ms=20, color=randColor(), direction='right'): time.sleep_ms(ms) self.np[i] = (0,0,0) - def fillStrip(self, ms=25, color=randColor()): + def fillStrip(self, ms=25, color=None): + if color == None: + color = self.randColor() count = self.np.n while count > 0: for i in range(count): @@ -42,7 +89,9 @@ def fillStrip(self, ms=25, color=randColor()): self.np[i] = (0,0,0) count -= 1 - def fillFromMiddle(self, ms=40, color=randColor()): + def fillFromMiddle(self, ms=40, color=None): + if color == None: + color = self.randColor() midpoint = int(self.np.n / 2) counter = 0 while counter != midpoint: @@ -55,7 +104,9 @@ def fillFromMiddle(self, ms=40, color=randColor()): time.sleep_ms(ms) counter += 1 - def fillFromSides(self, ms=40, color=randColor()): + def fillFromSides(self, ms=40, color=None): + if color == None: + color = self.randColor() midpoint = int(self.np.n / 2) counter = 0 while counter != midpoint: @@ -65,21 +116,25 @@ def fillFromSides(self, ms=40, color=randColor()): time.sleep_ms(ms) counter += 1 - def randomFill(self, ms=150, color=True): + def randomFill(self, ms=150, color=None): random_positions = [] while len(random_positions) < self.np.n: - random_pos = randInt(0, self.np.n) + random_pos = self.randInt(0, self.np.n) if random_pos not in random_positions: random_positions.append(random_pos) for position in random_positions: - if color == True: - self.np[position] = randColor() + if color == None: + self.np[position] = self.randColor() else: self.np[position] = color self.np.write() time.sleep_ms(ms) - def altColors(self, ms=125, firstColor=randColor(), secondColor=randColor()): + def altColors(self, ms=125, firstColor=None, secondColor=None): + if firstColor == None: + color = self.randColor() + if secondColor == None: + color = self.randColor() while True: for i in range(self.np.n): if i % 2 == 0: @@ -99,8 +154,8 @@ def altColors(self, ms=125, firstColor=randColor(), secondColor=randColor()): def bounce(self, ms=20, color=False): while True: if color == False: - self.chase(ms, randColor(), 'right') - self.chase(ms, randColor(), 'left') + self.chase(ms, self.randColor(), 'right') + self.chase(ms, self.randColor(), 'left') else: self.chase(ms, color, 'right') self.chase(ms, color, 'left') @@ -109,25 +164,25 @@ def rgbFade(self, ms=20): for channel in range(3): for v in range(256): if channel == 0: - self.setSegment(list(range(10)), (v,0,0)) + self.setSegment(list(range(self.np.n)), (v,0,0)) if channel == 1: - self.setSegment(list(range(10)), (0,v,0)) + self.setSegment(list(range(self.np.n)), (0,v,0)) if channel == 2: - self.setSegment(list(range(10)), (0,0,v)) + self.setSegment(list(range(self.np.n)), (0,0,v)) time.sleep_ms(ms) for v in range(255,-1,-1): if channel == 0: - self.setSegment(list(range(10)), (v,0,0)) + self.setSegment(list(range(self.np.n)), (v,0,0)) if channel == 1: - self.setSegment(list(range(10)), (0,v,0)) + self.setSegment(list(range(self.np.n)), (0,v,0)) if channel == 2: - self.setSegment(list(range(10)), (0,0,v)) + self.setSegment(list(range(self.np.n)), (0,0,v)) time.sleep_ms(ms) def rainbow(self, ms=20, iterations = 2): for j in range(256*iterations): for i in range(self.np.n): - self.np[i] = wheel(((i * 256 // self.np.n) + j) & 255) + self.np[i] = self.wheel(((i * 256 // self.np.n) + j) & 255) self.np.write() time.sleep_ms(ms) @@ -135,7 +190,7 @@ def rainbowChase(self, ms=50): for j in range(256): for q in range(3): for i in range(0, self.np.n, 3): - self.np[i+q] = wheel((i+j) % 255) + self.np[i+q] = self.wheel((i+j) % 255) self.np.write() time.sleep_ms(ms) for i in range(0, self.np.n, 3): @@ -158,7 +213,7 @@ def randInt(self, lower, upper): return upper - 1 def randColor(self): - return (randInt(0,256),randInt(0,256),randInt(0,256)) + return (self.randInt(0,256),self.randInt(0,256),self.randInt(0,256)) def wheel(self, pos): if pos < 85: