From de0505cf79db48bc023d939ec83276d8c19235d6 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Sun, 17 Jul 2022 22:22:16 -0600 Subject: [PATCH] Now it's network-aware --- LICENSE => LICENSE.md | 14 ++-- README.md | 7 +- network.cpp | 31 +++++++++ network.h | 10 +++ wallart.ino | 149 ++++++++++++++++++++++++++++++++++-------- wallart.py | 104 ----------------------------- 6 files changed, 172 insertions(+), 143 deletions(-) rename LICENSE => LICENSE.md (56%) create mode 100644 network.cpp create mode 100644 network.h delete mode 100644 wallart.py diff --git a/LICENSE b/LICENSE.md similarity index 56% rename from LICENSE rename to LICENSE.md index 62fa50e..7391599 100644 --- a/LICENSE +++ b/LICENSE.md @@ -12,10 +12,10 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The software is provided "as is", without warranty of any kind, express or +implied, including but not limited to the warranties of merchantability, +fitness for a particular purpose and noninfringement. In no event shall the +authors or copyright holders be liable for any claim, damages or other +liability, whether in an action of contract, tort or otherwise, arising from, +out of or in connection with the software or the use or other dealings in the +software. diff --git a/README.md b/README.md index 9d17b0b..00c6eb4 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,10 @@ Wall Art ======== -This is a CircuitPython port of an art piece I have -hanging in the wall of my office, with +This an art piece I have +hanging in the wall of my house, with pixels crammed into a cardboard box. -This port is running on a 1x1 stick of wood, -with tissue paper around it. - It doesn't display anything significant. The idea is to have something to look at if you're idle, without it being a distraction from more pressing issues. diff --git a/network.cpp b/network.cpp new file mode 100644 index 0000000..0951b56 --- /dev/null +++ b/network.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include "network.h" + +WiFiManager wfm; + +void network_setup(char *password) { + String hostid = String(ESP.getEfuseMac(), HEX); + String hostname = "Wall Art " + hostid; + + wfm.setConfigPortalBlocking(false); + wfm.setHostname(hostname); + wfm.autoConnect(hostname.c_str(), password); + + pinMode(LED_BUILTIN, OUTPUT); +} + +bool connected() { + return WiFi.status() == WL_CONNECTED; +} + +void pause(uint32_t dwMs) { + for (uint32_t t = 0; t < dwMs; t += 10) { + wfm.process(); + digitalWrite(LED_BUILTIN, connected()); + delay(10); + } +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..f1fc606 --- /dev/null +++ b/network.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + + +void network_setup(char *password); +bool connected(); +void pause(uint32_t dwMs); +void netget(int count); \ No newline at end of file diff --git a/wallart.ino b/wallart.ino index da497f4..ab68ec4 100644 --- a/wallart.ino +++ b/wallart.ino @@ -1,14 +1,23 @@ #include #include "picker.h" +#include "network.h" -#define NEOPIXEL_PIN 2 -#define GRIDLEN 50 +#define NEOPIXEL_PIN 32 +#define GRIDLEN 64 +#define WFM_PASSWORD "artsy fartsy" +#define ART_URL "https://sweetums.woozle.org/public/wallart.bin" #define MILLISECOND 1 #define SECOND (1000 * MILLISECOND) CRGB grid[GRIDLEN]; +void setup() { + FastLED.addLeds(grid, GRIDLEN); + FastLED.setBrightness(32); + network_setup(WFM_PASSWORD); +} + void fade(int cycles = 2) { int reps = (cycles*GRIDLEN) + random(GRIDLEN); int hue = random(256); @@ -17,15 +26,15 @@ void fade(int cycles = 2) { grid[(i+pos) % GRIDLEN] = CHSV(hue, 255, pos * 32); } FastLED.show(); - delay(80); + pause(80); } } void singleCursor(int count = 80) { - for (int i = 0; i < 80; i++) { + for (int i = 0; i < count; i++) { grid[20] = CHSV(0, 210, 127 * (i%2)); FastLED.show(); - delay(120); + pause(120); } } @@ -41,7 +50,7 @@ void sparkle(int cycles=50) { for (int j = 0; j < NUM_SPARKS; j++) { grid[pos[j]] = CRGB::Black; } - delay(40); + pause(40); } } @@ -76,11 +85,11 @@ void glitchPulse(int cycles=1000) { steps[i]--; } FastLED.show(); - delay(100); + pause(100); } } -void conwayish(int cycles=1000) { +void conwayish(int cycles=5000) { uint8_t total[GRIDLEN]; uint8_t left[GRIDLEN] = {0}; uint8_t hue = random(0, 64); @@ -104,29 +113,115 @@ void conwayish(int cycles=1000) { } } FastLED.show(); - delay(20); + pause(20); } } -void setup() { - FastLED.addLeds(grid, GRIDLEN); - FastLED.setBrightness(52); - pinMode(LED_BUILTIN, OUTPUT); +void cm5(int cycles=200) { + for (int frame = 0; frame < cycles; frame++) { + int val = 127 * random(2); + for (int pos = 0; pos < GRIDLEN; pos++) { + if (pos < GRIDLEN-1) { + grid[pos] = grid[pos + 1]; + } else { + grid[pos] = CHSV(0, 255, val); + } + } + FastLED.show(); + pause(500); + } } +// Art from the network +bool NetArtExists = false; +CRGB NetArt[GRIDLEN]; + +void netart() { + if (NetArtExists) { + memcpy(grid, NetArt, GRIDLEN*3); + FastLED.show(); + pause(10 * SECOND); + } +} + +int netgetStatus(int hue) { + static int positions[4] = {0}; + for (int j = 0; j < 4; j++) { + grid[positions[j]] = CHSV(0, 0, 0); + positions[j] = random(GRIDLEN); + grid[positions[j]] = CHSV(hue, 255, 180); + } + FastLED.show(); + pause(500); + return hue; +} + +void netget(int count=30) { + int hue = netgetStatus(HUE_BLUE); + + if (connected()) { + WiFiClientSecure scli; + + hue = netgetStatus(hue - 32); + scli.setInsecure(); + + { + HTTPClient https; + + if (https.begin(scli, ART_URL)) { + hue = netgetStatus(hue - 32); + int code = https.GET(); + if (code == HTTP_CODE_OK) { + hue = netgetStatus(hue - 32); + String resp = https.getString(); + for (int i = 0; i < resp.length(); i += 3) { + if (resp.length() < i+3) { + break; + } + CRGB pixel = CRGB(resp[i], resp[i+1], resp[i+2]); + NetArt[i/3] = rgb2hsv_approximate(pixel); + } + NetArtExists = true; + hue = hue - 32; + } + https.end(); + + FastLED.show(); + for (int i = 0; i < 4*4; i++) { + pause(250); + } + } + scli.stop(); + } + } + + for (int i = 0; i < count; i++) { + netgetStatus(hue); + } +} + + void loop() { - Picker p; + Picker p; - if (p.Pick(1)) { - fade(); - singleCursor(20); - } else if (p.Pick(1)) { - sparkle(); - } else if (p.Pick(4)) { - singleCursor(); - } else if (p.Pick(8)) { - conwayish(); - } else if (p.Pick(8)) { - glitchPulse(); - } -} \ No newline at end of file + if (p.Pick(1)) { + fade(); + singleCursor(20); + } else if (p.Pick(1)) { + sparkle(); + } else if (p.Pick(4)) { + singleCursor(); + } else if (p.Pick(8)) { + conwayish(); + } else if (p.Pick(8)) { + glitchPulse(); + } else if (p.Pick(8)) { + cm5(); + } else if (p.Pick(4) || !connected()) { + netget(); + } + + // trying to debug why we get freezing + grid[0] = CHSV(HUE_YELLOW, 255, 255); + FastLED.show(); +} diff --git a/wallart.py b/wallart.py deleted file mode 100644 index 285ab8d..0000000 --- a/wallart.py +++ /dev/null @@ -1,104 +0,0 @@ -import board -from digitalio import DigitalInOut, Direction, Pull -import adafruit_dotstar as dotstar -import adafruit_fancyled.adafruit_fancyled as fancy -import time -import neopixel -import random -import microcontroller - -# One pixel connected internally! -dot = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) -dot[0] = 0 - -# Built in red LED -led = DigitalInOut(board.D13) -led.direction = Direction.OUTPUT - -# NeoPixel strip (of 16 LEDs) connected on D4 -GRIDLEN = 64 -grid = neopixel.NeoPixel(board.D4, GRIDLEN, brightness=0.2, auto_write=False, pixel_order=neopixel.GRB) - - -class GlitchPixel: - def __init__(self): - self.init() - self.nsteps = 64 - self.step = random.randrange(self.nsteps) - - def init(self): - self.step = 0 - self.pos = random.randrange(GRIDLEN) - self.color = fancy.CHSV(random.random()).pack() - - def frame(self): - bmask = (0xff * self.step // 32) & 0xff - if self.step > self.nsteps/2: - bmask = 0xff - bmask - mask = (bmask << 16) | (bmask << 8) | (bmask << 0) - color = self.color & mask - grid[self.pos] = color - - self.step += 1 - if self.step > self.nsteps: - self.init() - -def fade(): - reps = 300 + random.randrange(GRIDLEN) - hue = random.randrange(256) - colors = [fancy.CHSV(hue, 255, v).pack() for v in range(0, 256, 32)] - rcolors = colors[:] - rcolors.reverse() - colors = colors + rcolors - for count in range(reps): - pos = count % GRIDLEN - for color in colors: - grid[pos] = color - pos -= 1 - grid.show() - -def singleCursor(): - red = fancy.CHSV(0, 210, 127).pack() - pos = 20 - for i in range(80): - grid[pos] = red * (i % 2) - led.value = not (i % 2) - grid.show() - time.sleep(0.08) - -def sparkle(): - white = fancy.CHSV(0, 0, 127).pack() - pos = [0,0,0] - for i in range(50): - for j in range(len(pos)): - pos[j] = random.randrange(GRIDLEN) - grid[pos[j]] = white - grid.show() - for p in pos: - grid[p] = 0 - grid.show() - -def glitchPulse(): - grid.fill(0) - pixels = [] - for i in range(4): - p = GlitchPixel() - pixels.append(p) - - for f in range(1000): - for p in pixels: - p.frame() - grid.show() - time.sleep(0.1) - -def loop(): - fade() - singleCursor() - sparkle() - glitchPulse() - # For some reason, this program freezes occasionally. - # I don't want to debug CircuitPython. - microcontroller.reset() - -while True: - loop()