├── Enclosure ├── PSU Box.stl ├── PSU Lid.stl ├── Wall Mount.stl ├── Display Mount.stl └── Glowing Square.f3d ├── GlowingSquare_Unifi ├── icons │ ├── up.png │ ├── down.png │ ├── down.psd │ ├── client.png │ ├── client.psd │ ├── globe.png │ ├── globe.psd │ └── guest.psd ├── web │ ├── config.example.php │ └── index.php ├── Patterns │ ├── Playlist.h │ ├── Drawable.h │ ├── Attractor.h │ ├── PatternSimplexNoise.h │ ├── Geometry.h │ ├── PatternWave.h │ ├── PatternFlock.h │ ├── PatternSnake.h │ ├── Vector.h │ ├── PatternSpiral.h │ └── Patterns.h ├── animations.h ├── icons.h ├── unifi.h ├── GlowingSquare_Unifi.ino ├── wifi.h ├── settings.h └── mqtt.h ├── .gitignore ├── GlowingSquare_Tube ├── example.secret.h ├── Patterns │ ├── Playlist.h │ ├── Drawable.h │ ├── Attractor.h │ ├── PatternSimplexNoise.h │ ├── Geometry.h │ ├── PatternWave.h │ ├── PatternFlock.h │ ├── Vector.h │ ├── PatternSnake.h │ ├── PatternSpiral.h │ └── Patterns.h ├── animations.h ├── GlowingSquare_Tube.ino ├── wifi.h ├── settings.h ├── mqtt.h ├── tubeapi.h └── display.h ├── GlowingSquare_Flight ├── Patterns │ ├── Playlist.h │ ├── Drawable.h │ ├── Attractor.h │ ├── PatternSimplexNoise.h │ ├── Geometry.h │ ├── PatternWave.h │ ├── PatternFlock.h │ ├── PatternSnake.h │ ├── Vector.h │ ├── PatternSpiral.h │ └── Patterns.h ├── animations.h ├── flightradar.h ├── GlowingSquare_Flight.ino ├── wifi.h ├── settings.h └── mqtt.h └── README.md /Enclosure/PSU Box.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/Enclosure/PSU Box.stl -------------------------------------------------------------------------------- /Enclosure/PSU Lid.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/Enclosure/PSU Lid.stl -------------------------------------------------------------------------------- /Enclosure/Wall Mount.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/Enclosure/Wall Mount.stl -------------------------------------------------------------------------------- /Enclosure/Display Mount.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/Enclosure/Display Mount.stl -------------------------------------------------------------------------------- /Enclosure/Glowing Square.f3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/Enclosure/Glowing Square.f3d -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/up.png -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/down.png -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/down.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/down.psd -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/client.png -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/client.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/client.psd -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/globe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/globe.png -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/globe.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/globe.psd -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons/guest.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfo/GlowingSquare/HEAD/GlowingSquare_Unifi/icons/guest.psd -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all logs 2 | *.log 3 | 4 | .DS_Store 5 | 6 | config.php 7 | 8 | secret.h 9 | 10 | Icon\r\r 11 | Icon[ ] 12 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/example.secret.h: -------------------------------------------------------------------------------- 1 | // Get your own from https://api-portal.tfl.gov.uk/ 2 | #define TFL_APP_ID "asdf" 3 | #define TFL_APP_KEY "asdf" 4 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/web/config.example.php: -------------------------------------------------------------------------------- 1 | < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | animations.h 14 | * 15 | */ 16 | 17 | #include "Patterns/Effects.h" 18 | Effects effects; 19 | 20 | #include "Patterns/Drawable.h" 21 | #include "Patterns/Playlist.h" 22 | 23 | #include "Patterns/Patterns.h" 24 | Patterns patterns; 25 | 26 | /* 27 | 28 | Patterns: 29 | "0: Noise", 30 | "1: Wave", 31 | "2: Flock", 32 | "3: Snake", 33 | "4: Spiral" 34 | 35 | */ 36 | 37 | unsigned long ms_current = 0; 38 | unsigned long ms_previous = 0; 39 | unsigned long next_frame = 0; 40 | 41 | 42 | void setupAnimations() { 43 | // Load the effects into memory 44 | effects.Setup(); 45 | 46 | // Just a placeholder until we set it again later 47 | patterns.setPattern(1); 48 | patterns.start(); 49 | } 50 | 51 | 52 | void patternLoop() { 53 | 54 | // Switch the pattern when the party_mode is changed 55 | // But only if it's changed since the last loop 56 | if (party_mode != last_party_mode) { 57 | 58 | // Required to make the transition good 59 | patterns.stop(); 60 | 61 | // Set the patterns for each mode 62 | if (party_mode == 1) 63 | patterns.setPattern(1); 64 | else 65 | patterns.setPattern(4); 66 | 67 | // Make sure we don't run this again 68 | last_party_mode = party_mode; 69 | 70 | // Resume the pattern display 71 | patterns.start(); 72 | } 73 | 74 | ms_current = millis(); 75 | 76 | int frame_delay = 0; 77 | 78 | if (party_mode == 1) { 79 | frame_delay = 20; 80 | } 81 | 82 | if (next_frame < ms_current) { 83 | next_frame = patterns.drawFrame() + ms_current + frame_delay; 84 | display.showBuffer(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/animations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | animations.h 14 | * 15 | */ 16 | 17 | #include "Patterns/Effects.h" 18 | Effects effects; 19 | 20 | #include "Patterns/Drawable.h" 21 | #include "Patterns/Playlist.h" 22 | 23 | #include "Patterns/Patterns.h" 24 | Patterns patterns; 25 | 26 | /* 27 | 28 | Patterns: 29 | "0: Noise", 30 | "1: Wave", 31 | "2: Flock", 32 | "3: Snake", 33 | "4: Spiral" 34 | 35 | */ 36 | 37 | unsigned long ms_current = 0; 38 | unsigned long ms_previous = 0; 39 | unsigned long next_frame = 0; 40 | 41 | 42 | void setupAnimations() { 43 | // Load the effects into memory 44 | effects.Setup(); 45 | 46 | // Just a placeholder until we set it again later 47 | patterns.setPattern(1); 48 | patterns.start(); 49 | } 50 | 51 | 52 | void patternLoop() { 53 | 54 | // Switch the pattern when the party_mode is changed 55 | // But only if it's changed since the last loop 56 | if (party_mode != last_party_mode) { 57 | 58 | // Required to make the transition good 59 | patterns.stop(); 60 | 61 | // Set the patterns for each mode 62 | if (party_mode == 1) 63 | patterns.setPattern(1); 64 | else 65 | patterns.setPattern(4); 66 | 67 | // Make sure we don't run this again 68 | last_party_mode = party_mode; 69 | 70 | // Resume the pattern display 71 | patterns.start(); 72 | } 73 | 74 | ms_current = millis(); 75 | 76 | int frame_delay = 0; 77 | 78 | if (party_mode == 1) { 79 | frame_delay = 20; 80 | } 81 | 82 | if (next_frame < ms_current) { 83 | next_frame = patterns.drawFrame() + ms_current + frame_delay; 84 | display.showBuffer(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/animations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | animations.h 14 | * 15 | */ 16 | 17 | #include "Patterns/Effects.h" 18 | Effects effects; 19 | 20 | #include "Patterns/Drawable.h" 21 | #include "Patterns/Playlist.h" 22 | 23 | #include "Patterns/Patterns.h" 24 | Patterns patterns; 25 | 26 | /* 27 | 28 | Patterns: 29 | "0: Noise", 30 | "1: Wave", 31 | "2: Flock", 32 | "3: Snake", 33 | "4: Spiral" 34 | 35 | */ 36 | 37 | unsigned long ms_current = 0; 38 | unsigned long ms_previous = 0; 39 | unsigned long next_frame = 0; 40 | 41 | 42 | void setupAnimations() { 43 | // Load the effects into memory 44 | effects.Setup(); 45 | 46 | // Just a placeholder until we set it again later 47 | patterns.setPattern(1); 48 | patterns.start(); 49 | } 50 | 51 | 52 | void patternLoop() { 53 | 54 | // Switch the pattern when the party_mode is changed 55 | // But only if it's changed since the last loop 56 | if (party_mode != last_party_mode) { 57 | 58 | // Required to make the transition good 59 | patterns.stop(); 60 | 61 | // Set the patterns for each mode 62 | if (party_mode == 1) 63 | patterns.setPattern(1); 64 | else 65 | patterns.setPattern(4); 66 | 67 | // Make sure we don't run this again 68 | last_party_mode = party_mode; 69 | 70 | // Resume the pattern display 71 | patterns.start(); 72 | } 73 | 74 | ms_current = millis(); 75 | 76 | int frame_delay = 0; 77 | 78 | if (party_mode == 1) { 79 | frame_delay = 20; 80 | } 81 | 82 | if (next_frame < ms_current) { 83 | next_frame = patterns.drawFrame() + ms_current + frame_delay; 84 | display.showBuffer(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/Drawable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Drawable_H 24 | #define Drawable_H 25 | 26 | class Drawable{ 27 | public: 28 | char* name; 29 | 30 | virtual bool isRunnable() { 31 | return false; 32 | } 33 | 34 | virtual bool isPlaylist() { 35 | return false; 36 | } 37 | 38 | // a single frame should be drawn as fast as possible, without any delay or blocking 39 | // return how many millisecond delay is requested before the next call to drawFrame() 40 | virtual unsigned int drawFrame() { 41 | display.fillScreen(0); 42 | //backgroundLayer.fillScreen({ 0, 0, 0 }); 43 | return 0; 44 | }; 45 | 46 | virtual void printTesting() 47 | { 48 | Serial.println("Testing..."); 49 | } 50 | 51 | virtual void start() {}; 52 | virtual void stop() {}; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/Drawable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Drawable_H 24 | #define Drawable_H 25 | 26 | class Drawable{ 27 | public: 28 | char* name; 29 | 30 | virtual bool isRunnable() { 31 | return false; 32 | } 33 | 34 | virtual bool isPlaylist() { 35 | return false; 36 | } 37 | 38 | // a single frame should be drawn as fast as possible, without any delay or blocking 39 | // return how many millisecond delay is requested before the next call to drawFrame() 40 | virtual unsigned int drawFrame() { 41 | display.fillScreen(0); 42 | //backgroundLayer.fillScreen({ 0, 0, 0 }); 43 | return 0; 44 | }; 45 | 46 | virtual void printTesting() 47 | { 48 | Serial.println("Testing..."); 49 | } 50 | 51 | virtual void start() {}; 52 | virtual void stop() {}; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/Drawable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Drawable_H 24 | #define Drawable_H 25 | 26 | class Drawable{ 27 | public: 28 | char* name; 29 | 30 | virtual bool isRunnable() { 31 | return false; 32 | } 33 | 34 | virtual bool isPlaylist() { 35 | return false; 36 | } 37 | 38 | // a single frame should be drawn as fast as possible, without any delay or blocking 39 | // return how many millisecond delay is requested before the next call to drawFrame() 40 | virtual unsigned int drawFrame() { 41 | display.fillScreen(0); 42 | //backgroundLayer.fillScreen({ 0, 0, 0 }); 43 | return 0; 44 | }; 45 | 46 | virtual void printTesting() 47 | { 48 | Serial.println("Testing..."); 49 | } 50 | 51 | virtual void start() {}; 52 | virtual void stop() {}; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/icons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | icons.h 14 | * 15 | */ 16 | 17 | // Client Icon 18 | const uint16_t ccolor = display.color565(247, 35, 12); 19 | 20 | static const uint16_t client_icon[49] PROGMEM={ 21 | ccolor, ccolor, ccolor, ccolor, 0x0000, 0x0000, 0x0000, 22 | 0x0000, 0x0000, 0x0000, 0x0000, ccolor, ccolor, 0x0000, 23 | ccolor, ccolor, ccolor, 0x0000, 0x0000, ccolor, 0x0000, 24 | 0x0000, 0x0000, 0x0000, ccolor, 0x0000, 0x0000, ccolor, 25 | 0x0000, 0x0000, 0x0000, 0x0000, ccolor, 0x0000, ccolor, 26 | ccolor, ccolor, 0x0000, 0x0000, ccolor, 0x0000, ccolor, 27 | ccolor, ccolor, 0x0000, 0x0000, ccolor, 0x0000, ccolor 28 | }; 29 | 30 | // Guest Icon 31 | const uint16_t gcolor = display.color565(247, 35, 12); 32 | 33 | static const uint16_t guest_icon[49] PROGMEM={ 34 | 0x0000, 0x0000, 0x0000, gcolor, 0x0000, 0x0000, 0x0000, 35 | 0x0000, 0x0000, gcolor, gcolor, gcolor, 0x0000, 0x0000, 36 | 0x0000, 0x0000, gcolor, gcolor, gcolor, 0x0000, 0x0000, 37 | 0x0000, 0x0000, gcolor, gcolor, gcolor, 0x0000, 0x0000, 38 | 0x0000, 0x0000, 0x0000, gcolor, 0x0000, 0x0000, 0x0000, 39 | 0x0000, gcolor, gcolor, gcolor, gcolor, gcolor, 0x0000, 40 | 0x0000, gcolor, gcolor, gcolor, gcolor, gcolor, 0x0000 41 | }; 42 | 43 | // Up Icon 44 | const uint16_t ucolor = display.color565(204, 20, 170); 45 | 46 | static const uint16_t up_icon[35] PROGMEM={ 47 | 0x0000, 0x0000, ucolor, 0x0000, 0x0000, 48 | 0x0000, ucolor, ucolor, ucolor, 0x0000, 49 | ucolor, 0x0000, ucolor, 0x0000, ucolor, 50 | 0x0000, 0x0000, ucolor, 0x0000, 0x0000, 51 | 0x0000, 0x0000, ucolor, 0x0000, 0x0000, 52 | 0x0000, 0x0000, ucolor, 0x0000, 0x0000, 53 | 0x0000, 0x0000, ucolor, 0x0000, 0x0000 54 | }; 55 | 56 | // Down Icon 57 | const uint16_t dcolor = display.color565(250, 88, 12); 58 | 59 | static const uint16_t down_icon[35] PROGMEM={ 60 | 0x0000, 0x0000, dcolor, 0x0000, 0x0000, 61 | 0x0000, 0x0000, dcolor, 0x0000, 0x0000, 62 | 0x0000, 0x0000, dcolor, 0x0000, 0x0000, 63 | 0x0000, 0x0000, dcolor, 0x0000, 0x0000, 64 | dcolor, 0x0000, dcolor, 0x0000, dcolor, 65 | 0x0000, dcolor, dcolor, dcolor, 0x0000, 66 | 0x0000, 0x0000, dcolor, 0x0000, 0x0000 67 | }; 68 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/Attractor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Attractor" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | #include "Vector.h" 28 | 29 | class Attractor { 30 | public: 31 | float mass; // Mass, tied to size 32 | float G; // Gravitational Constant 33 | PVector location; // Location 34 | 35 | Attractor() { 36 | location = PVector(MATRIX_CENTRE_X, MATRIX_CENTRE_Y); 37 | mass = 10; 38 | G = .5; 39 | } 40 | 41 | PVector attract(Boid m) { 42 | PVector force = location - m.location; // Calculate direction of force 43 | float d = force.mag(); // Distance between objects 44 | d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects 45 | force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) 46 | float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude 47 | force *= strength; // Get force vector --> magnitude * direction 48 | return force; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/Attractor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Attractor" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | #include "Vector.h" 28 | 29 | class Attractor { 30 | public: 31 | float mass; // Mass, tied to size 32 | float G; // Gravitational Constant 33 | PVector location; // Location 34 | 35 | Attractor() { 36 | location = PVector(MATRIX_CENTRE_X, MATRIX_CENTRE_Y); 37 | mass = 10; 38 | G = .5; 39 | } 40 | 41 | PVector attract(Boid m) { 42 | PVector force = location - m.location; // Calculate direction of force 43 | float d = force.mag(); // Distance between objects 44 | d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects 45 | force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) 46 | float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude 47 | force *= strength; // Get force vector --> magnitude * direction 48 | return force; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/Attractor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Attractor" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | #include "Vector.h" 28 | 29 | class Attractor { 30 | public: 31 | float mass; // Mass, tied to size 32 | float G; // Gravitational Constant 33 | PVector location; // Location 34 | 35 | Attractor() { 36 | location = PVector(MATRIX_CENTRE_X, MATRIX_CENTRE_Y); 37 | mass = 10; 38 | G = .5; 39 | } 40 | 41 | PVector attract(Boid m) { 42 | PVector force = location - m.location; // Calculate direction of force 43 | float d = force.mag(); // Distance between objects 44 | d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects 45 | force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) 46 | float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude 47 | force *= strength; // Get force vector --> magnitude * direction 48 | return force; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/PatternSimplexNoise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Noise/Noise.ino 6 | * Copyright (c) 2013 FastLED 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSimplexNoise_H 27 | #define PatternSimplexNoise_H 28 | 29 | class PatternSimplexNoise : public Drawable { 30 | public: 31 | PatternSimplexNoise() { 32 | name = (char *)"Noise"; 33 | } 34 | 35 | void start() { 36 | // Initialize our coordinates to some random values 37 | noise_x = random16(); 38 | noise_y = random16(); 39 | noise_z = random16(); 40 | } 41 | 42 | unsigned int drawFrame() { 43 | #if FASTLED_VERSION >= 3001000 44 | // a new parameter set every 15 seconds 45 | EVERY_N_SECONDS(15) { 46 | noise_x = random16(); 47 | noise_y = random16(); 48 | noise_z = random16(); 49 | } 50 | #endif 51 | 52 | uint32_t speed = 100; 53 | 54 | effects.FillNoise(); 55 | ShowNoiseLayer(0, 1, 0); 56 | 57 | // noise_x += speed; 58 | noise_y += speed; 59 | noise_z += speed; 60 | 61 | effects.ShowFrame(); 62 | 63 | return 0; 64 | } 65 | 66 | // show just one layer 67 | void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) { 68 | for (uint8_t i = 0; i < MATRIX_WIDTH; i++) { 69 | for (uint8_t j = 0; j < MATRIX_HEIGHT; j++) { 70 | uint8_t pixel = noise[i][j]; 71 | 72 | // assign a color depending on the actual palette 73 | effects.leds[XY(i, j)] = effects.ColorFromCurrentPalette(colorrepeat * (pixel + colorshift), pixel); 74 | } 75 | } 76 | } 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/PatternSimplexNoise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Noise/Noise.ino 6 | * Copyright (c) 2013 FastLED 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSimplexNoise_H 27 | #define PatternSimplexNoise_H 28 | 29 | class PatternSimplexNoise : public Drawable { 30 | public: 31 | PatternSimplexNoise() { 32 | name = (char *)"Noise"; 33 | } 34 | 35 | void start() { 36 | // Initialize our coordinates to some random values 37 | noise_x = random16(); 38 | noise_y = random16(); 39 | noise_z = random16(); 40 | } 41 | 42 | unsigned int drawFrame() { 43 | #if FASTLED_VERSION >= 3001000 44 | // a new parameter set every 15 seconds 45 | EVERY_N_SECONDS(15) { 46 | noise_x = random16(); 47 | noise_y = random16(); 48 | noise_z = random16(); 49 | } 50 | #endif 51 | 52 | uint32_t speed = 100; 53 | 54 | effects.FillNoise(); 55 | ShowNoiseLayer(0, 1, 0); 56 | 57 | // noise_x += speed; 58 | noise_y += speed; 59 | noise_z += speed; 60 | 61 | effects.ShowFrame(); 62 | 63 | return 0; 64 | } 65 | 66 | // show just one layer 67 | void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) { 68 | for (uint8_t i = 0; i < MATRIX_WIDTH; i++) { 69 | for (uint8_t j = 0; j < MATRIX_HEIGHT; j++) { 70 | uint8_t pixel = noise[i][j]; 71 | 72 | // assign a color depending on the actual palette 73 | effects.leds[XY(i, j)] = effects.ColorFromCurrentPalette(colorrepeat * (pixel + colorshift), pixel); 74 | } 75 | } 76 | } 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/PatternSimplexNoise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Noise/Noise.ino 6 | * Copyright (c) 2013 FastLED 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSimplexNoise_H 27 | #define PatternSimplexNoise_H 28 | 29 | class PatternSimplexNoise : public Drawable { 30 | public: 31 | PatternSimplexNoise() { 32 | name = (char *)"Noise"; 33 | } 34 | 35 | void start() { 36 | // Initialize our coordinates to some random values 37 | noise_x = random16(); 38 | noise_y = random16(); 39 | noise_z = random16(); 40 | } 41 | 42 | unsigned int drawFrame() { 43 | #if FASTLED_VERSION >= 3001000 44 | // a new parameter set every 15 seconds 45 | EVERY_N_SECONDS(15) { 46 | noise_x = random16(); 47 | noise_y = random16(); 48 | noise_z = random16(); 49 | } 50 | #endif 51 | 52 | uint32_t speed = 100; 53 | 54 | effects.FillNoise(); 55 | ShowNoiseLayer(0, 1, 0); 56 | 57 | // noise_x += speed; 58 | noise_y += speed; 59 | noise_z += speed; 60 | 61 | effects.ShowFrame(); 62 | 63 | return 0; 64 | } 65 | 66 | // show just one layer 67 | void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) { 68 | for (uint8_t i = 0; i < MATRIX_WIDTH; i++) { 69 | for (uint8_t j = 0; j < MATRIX_HEIGHT; j++) { 70 | uint8_t pixel = noise[i][j]; 71 | 72 | // assign a color depending on the actual palette 73 | effects.leds[XY(i, j)] = effects.ColorFromCurrentPalette(colorrepeat * (pixel + colorshift), pixel); 74 | } 75 | } 76 | } 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/flightradar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | flightradar.h 14 | * 15 | */ 16 | 17 | #define OFFSETX 0 18 | 19 | // Keep track of any failed web requests 20 | int failed_attempts = 0; 21 | 22 | // Struct to store the information about the downloaded flight 23 | struct Flight { 24 | char from[4]; 25 | char to[4]; 26 | char number[8]; 27 | char reg[12]; 28 | char aircraft[12]; 29 | unsigned int speed; 30 | unsigned int altitude; 31 | }; 32 | 33 | // This is what we'll store the processed departures in 34 | Flight flight; 35 | 36 | // Function that runs from loop() every 60 seconds 37 | boolean downloadFlightInfo() { 38 | 39 | HTTPClient http; 40 | 41 | // This is the API endpoint that we fetch new departures for our station from 42 | char requestURL[256]; 43 | sprintf(requestURL, "http://data-live.flightradar24.com/zones/fcgi/feed.js?bounds=%s&faa=1&satellite=1&mlat=1&flarm=1&adsb=1&gnd=0&air=1&vehicles=0&estimated=0&maxage=14400&gliders=0&stats=0&ems=1&limit=1", flight_area); 44 | 45 | // Fetch the data from the server 46 | http.begin(requestURL); 47 | int httpCode = http.GET(); 48 | 49 | // Check that the server gave a valid response 50 | if (httpCode != 200) { 51 | Serial.printf("Failed to get info with HTTP Code %i\n", httpCode); // Code -11 means the request timed out 52 | 53 | // Mark us as offline so the little icon will be drawn next time 54 | failed_attempts++; 55 | return false; 56 | 57 | } else { 58 | // All is good 59 | failed_attempts = 0; 60 | } 61 | 62 | String payload = http.getString(); 63 | 64 | StaticJsonDocument<2048> json; 65 | deserializeJson(json, payload); 66 | 67 | JsonObject object = json.as(); 68 | 69 | if (object.size() < 3) { 70 | Serial.println("No flight found"); 71 | return false; 72 | } 73 | 74 | auto it = object.begin(); 75 | it += 2; 76 | JsonArray values = it->value(); 77 | 78 | flight.altitude = values[4]; 79 | flight.speed = values[5]; 80 | strcpy(flight.aircraft, values[8]); 81 | strcpy(flight.reg, values[9]); 82 | strcpy(flight.from, values[11]); 83 | strcpy(flight.to, values[12]); 84 | strcpy(flight.number, values[13]); 85 | 86 | Serial.printf("Downloaded flight: %s (%s %s) from %s to %s at %ikts %ift\n", flight.number, flight.aircraft, flight.reg, flight.from, flight.to, flight.speed, flight.altitude); 87 | 88 | return true; 89 | 90 | } 91 | 92 | void displayFlightInfo() { 93 | 94 | display.clearDisplay(); 95 | display.setTextColor(myCYAN); 96 | 97 | display.setCursor(OFFSETX,0); 98 | display.print(flight.from); 99 | display.setTextColor(myCYAN); 100 | display.print(">"); 101 | 102 | display.print(flight.to); 103 | display.setCursor(OFFSETX,8); 104 | display.setTextColor(myWHITE); 105 | display.print(flight.number); 106 | if(flight.altitude>10000) display.setTextColor(myGREEN); 107 | else display.setTextColor(myRED); 108 | display.setCursor(OFFSETX,16); 109 | display.print(flight.altitude); 110 | display.print("ft"); 111 | display.setCursor(OFFSETX,24); 112 | display.setTextColor(myWHITE); 113 | display.print(flight.speed); 114 | display.print("kts"); 115 | display.setTextColor(myCYAN); 116 | display.print(flight.aircraft); 117 | 118 | display.showBuffer(); 119 | 120 | } 121 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/unifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | unifi.h 14 | * 15 | */ 16 | 17 | // How tall we want the graph on the display to be 18 | #define GRAPH_HEIGHT 8 19 | 20 | // Keep track of any failed web requests 21 | int failed_attempts = 0; 22 | 23 | // Function that runs from loop() every 30 seconds 24 | boolean downloadAndDisplayNetworkInfo() { 25 | 26 | Serial.print("Fetching info... "); 27 | 28 | HTTPClient http; 29 | 30 | // This is the API endpoint that we fetch new departures for our station from 31 | char requestURL[256]; 32 | sprintf(requestURL, "%s?width=%i&height=%i", script_url, MATRIX_WIDTH, GRAPH_HEIGHT); 33 | 34 | // Fetch the data from the server 35 | http.begin(requestURL); 36 | int httpCode = http.GET(); 37 | 38 | // Check that the server gave a valid response 39 | if (httpCode != 200) { 40 | Serial.printf("Failed to get info with HTTP Code %i\n", httpCode); // Code -11 means the request timed out 41 | 42 | // Mark us as offline so the little icon will be drawn next time 43 | failed_attempts++; 44 | return false; 45 | 46 | } else { 47 | // All is good 48 | failed_attempts = 0; 49 | } 50 | 51 | // Fetch and parse the web request 52 | String payload = http.getString(); 53 | 54 | StaticJsonDocument<2048> json; 55 | deserializeJson(json, payload); 56 | 57 | // Start writing to the display 58 | display.clearDisplay(); 59 | 60 | // Draw the download icon and stats 61 | drawIcon(0, 0, 5, 7, down_icon); 62 | display.setCursor(6,0); 63 | display.setTextColor(display.color565(250, 50, 12)); 64 | display.print(json["month_rx"].as()); 65 | 66 | // Draw the upload icon and stats 67 | drawIcon(MATRIX_WIDTH - 5, 0, 5, 7, up_icon); 68 | display.setTextColor(display.color565(110, 10, 204)); 69 | drawRightAlignedText(MATRIX_WIDTH - 5, 0, json["month_tx"].as()); 70 | 71 | // Draw the client icon and stats 72 | drawIcon(0, 8, 7, 7, client_icon); 73 | display.setCursor(9,8); 74 | display.setTextColor(display.color565(247, 20, 12)); 75 | display.print(json["clients"].as()); 76 | 77 | // Calculate where the guest icon and text needs to go 78 | int next_x = 14 + json["clients"].as().length() * 5; 79 | 80 | // Draw the guest icon and stats 81 | drawIcon(next_x, 8, 7, 7, guest_icon); 82 | display.setCursor(next_x + 8, 8); 83 | display.print(json["guests"].as()); 84 | 85 | // Draw the graph of network activity 86 | // Loop along the x axis of the graph 87 | for (int x = 0; x < MATRIX_WIDTH; x++) { 88 | 89 | // Draw the columns pixel by pixel 90 | for (int y = 0; y < json["graph"][x]; y++) { 91 | display.drawPixel(x, MATRIX_HEIGHT - 1 - y, display.color565(21, 58, 234)); 92 | } 93 | 94 | } 95 | 96 | // Draw the newest client stuff 97 | // We do this last because it is a blocking animation 98 | // Only display if the new device is less than 2 mins old 99 | if (json["min_uptime"] < (INFO_UPDATE_INTERVAL * 4 / 1000)) { 100 | drawStaticAndScrollingText(16, 50, "New:", json["newest"].as(), 247, 10, 12, 128, 5, 6); 101 | } else { 102 | // Remove what was there before 103 | fillBlankRow(16); 104 | } 105 | 106 | display.showBuffer(); 107 | 108 | Serial.printf("%s down %s up\n", json["month_rx"].as(), json["month_tx"].as()); 109 | 110 | } 111 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/GlowingSquare_Unifi.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | GlowingSquare_Unifi.ino 14 | * 15 | */ 16 | 17 | // Include Libraries 18 | #include // this needs to be first, or it all crashes and burns... 19 | #include // https://github.com/tzapu/WiFiManager ~v2.0.0 20 | #include // https://github.com/bblanchon/ArduinoJson ~v6.x.x 21 | #include // https://github.com/knolleary/pubsubclient ~v2.7.0 22 | #include // Included with core 23 | #include // To fetch data 24 | // PxMatrix is included from inside the display.h file 25 | #include // For the animations during party mode 26 | 27 | #ifdef ESP32 28 | #include 29 | #endif 30 | 31 | // Uncomment to reset device memory (useful to fix corruption / force new settings) 32 | //#define START_ANEW 33 | 34 | int party_mode = 0; // 0 = off, 1 = chill, 2 = party 35 | int last_party_mode = party_mode; 36 | uint8_t targetDisplayBrightness = 255; 37 | uint8_t currentDisplayBrightness = 255; 38 | 39 | #define INFO_UPDATE_INTERVAL 30000 40 | 41 | // Include the other sketch files 42 | #include "settings.h" 43 | #include "display.h" 44 | #include "icons.h" 45 | #include "wifi.h" 46 | #include "unifi.h" 47 | #include "animations.h" 48 | #include "mqtt.h" 49 | 50 | void setup() { 51 | 52 | // Start serial 53 | Serial.begin(115200); 54 | Serial.println(); 55 | 56 | // Load config from the file system 57 | setupStorage(); 58 | 59 | // Start up WiFi and config parameters etc. 60 | startWiFiManagerWithParameters(); 61 | 62 | // Must go after the SPIFFs stuff or we crash the ESP32 63 | setupDisplay(); 64 | 65 | // Start ArduinoOTA service 66 | // So not just anyone can re-flash our devices 67 | ArduinoOTA.setPassword("chvFSEebm9X4GtpY"); 68 | ArduinoOTA.begin(); 69 | 70 | // Instantiate MQTT 71 | setupMQTT(); 72 | 73 | setupAnimations(); 74 | 75 | } 76 | 77 | // Variables just for the example code below 78 | long lastWebRequest = -INFO_UPDATE_INTERVAL; 79 | 80 | void loop() { 81 | 82 | // All-purpose way to keep track of the time 83 | long now = millis(); 84 | 85 | // Loop our network services 86 | mqttLoop(); // Non-blocking MQTT connect/re-connect 87 | ArduinoOTA.handle(); // In case we want to upload a new sketch 88 | 89 | // Show tube stuff only if party mode is off 90 | if (party_mode == 0) { 91 | 92 | // We need to use the blocking fade because the 93 | // actual displaying of info is blocking too 94 | changeBrightnessBlocking(3000); 95 | 96 | // Only download new info every 10 seconds 97 | if (now - lastWebRequest > INFO_UPDATE_INTERVAL && currentDisplayBrightness != 0) { 98 | 99 | downloadAndDisplayNetworkInfo(); 100 | 101 | // Only display as offline if we've had 3 failed web requests in a row 102 | if (failed_attempts > 2) { 103 | displayOffline(); 104 | } 105 | 106 | // Create a debug message 107 | lastWebRequest = now; 108 | 109 | } 110 | 111 | } else { 112 | 113 | // Use a non-blocking fade so the animation can continue 114 | // smoothly as we fade 115 | changeBrightnessNonBlocking(); 116 | 117 | // Draw the next frame of our patterns 118 | patternLoop(); 119 | 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/GlowingSquare_Flight.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | GlowingSquare_Flight.ino 14 | * 15 | */ 16 | 17 | // Include Libraries 18 | #include // this needs to be first, or it all crashes and burns... 19 | #include // https://github.com/tzapu/WiFiManager ~v2.0.0 20 | #include // https://github.com/bblanchon/ArduinoJson ~v6.x.x 21 | #include // https://github.com/knolleary/pubsubclient ~v2.7.0 22 | #include // Included with core 23 | #include // To fetch data 24 | // PxMatrix is included from inside the display.h file 25 | #include // For the animations during party mode 26 | 27 | #ifdef ESP32 28 | #include 29 | #endif 30 | 31 | // Uncomment to reset device memory (useful to fix corruption / force new settings) 32 | //#define START_ANEW 33 | 34 | int party_mode = 0; // 0 = off, 1 = chill, 2 = party 35 | int last_party_mode = party_mode; 36 | uint8_t targetDisplayBrightness = 255; 37 | uint8_t currentDisplayBrightness = 255; 38 | 39 | #define INFO_UPDATE_INTERVAL 10000 40 | 41 | // Include the other sketch files 42 | #include "settings.h" 43 | #include "display.h" 44 | #include "wifi.h" 45 | #include "flightradar.h" 46 | #include "animations.h" 47 | #include "mqtt.h" 48 | 49 | void setup() { 50 | 51 | // Start serial 52 | Serial.begin(115200); 53 | Serial.println(); 54 | 55 | // Load config from the file system 56 | setupStorage(); 57 | 58 | // Start up WiFi and config parameters etc. 59 | startWiFiManagerWithParameters(); 60 | 61 | // Must go after the SPIFFs stuff or we crash the ESP32 62 | setupDisplay(); 63 | 64 | // Start ArduinoOTA service 65 | // So not just anyone can re-flash our devices 66 | ArduinoOTA.setPassword("chvFSEebm9X4GtpY"); 67 | ArduinoOTA.begin(); 68 | 69 | // Instantiate MQTT 70 | setupMQTT(); 71 | 72 | setupAnimations(); 73 | 74 | } 75 | 76 | // Variables just for the example code below 77 | long lastWebRequest = -INFO_UPDATE_INTERVAL; 78 | 79 | void loop() { 80 | 81 | // All-purpose way to keep track of the time 82 | long now = millis(); 83 | 84 | // Loop our network services 85 | mqttLoop(); // Non-blocking MQTT connect/re-connect 86 | ArduinoOTA.handle(); // In case we want to upload a new sketch 87 | 88 | // Show tube stuff only if party mode is off 89 | if (party_mode == 0) { 90 | 91 | // We need to use the blocking fade because the 92 | // actual displaying of info is blocking too 93 | changeBrightnessBlocking(3000); 94 | 95 | // Only download new info every 10 seconds 96 | if (now - lastWebRequest > INFO_UPDATE_INTERVAL && currentDisplayBrightness != 0) { 97 | 98 | downloadFlightInfo(); 99 | 100 | // Only display as offline if we've had 3 failed web requests in a row 101 | if (failed_attempts > 2) { 102 | displayOffline(); 103 | } else { 104 | displayFlightInfo(); 105 | } 106 | 107 | // Create a debug message 108 | lastWebRequest = now; 109 | 110 | } 111 | 112 | } else { 113 | 114 | // Use a non-blocking fade so the animation can continue 115 | // smoothly as we fade 116 | changeBrightnessNonBlocking(); 117 | 118 | // Draw the next frame of our patterns 119 | patternLoop(); 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/GlowingSquare_Tube.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | GlowingSquare_Tube.ino 14 | * 15 | */ 16 | 17 | // Include Libraries 18 | #include // this needs to be first, or it all crashes and burns... 19 | #include // https://github.com/tzapu/WiFiManager ~v2.0.0 20 | #include // https://github.com/bblanchon/ArduinoJson ~v6.x.x 21 | #include // https://github.com/knolleary/pubsubclient ~v2.7.0 22 | #include // Included with core 23 | #include // To fetch data 24 | // PxMatrix is included from inside the display.h file 25 | #include // For the animations during party mode 26 | 27 | #ifdef ESP32 28 | #include 29 | #endif 30 | 31 | // Uncomment to reset device memory (useful to fix corruption / force new settings) 32 | //#define START_ANEW 33 | 34 | int party_mode = 0; // 0 = off, 1 = chill, 2 = party 35 | int last_party_mode = party_mode; 36 | uint8_t targetDisplayBrightness = 255; 37 | uint8_t currentDisplayBrightness = 255; 38 | 39 | #define INFO_UPDATE_INTERVAL 60000 40 | 41 | // Include the other sketch files 42 | #include "settings.h" 43 | #include "display.h" 44 | #include "wifi.h" 45 | #include "tubeapi.h" 46 | #include "animations.h" 47 | #include "mqtt.h" 48 | 49 | void setup() { 50 | 51 | // Start serial 52 | Serial.begin(115200); 53 | Serial.println(); 54 | 55 | // Load config from the file system 56 | setupStorage(); 57 | 58 | // Start up WiFi and config parameters etc. 59 | startWiFiManagerWithParameters(); 60 | 61 | // Must go after the SPIFFs stuff or we crash the ESP32 62 | setupDisplay(); 63 | 64 | // Start ArduinoOTA service 65 | // So not just anyone can re-flash our devices 66 | ArduinoOTA.setPassword("chvFSEebm9X4GtpY"); 67 | ArduinoOTA.begin(); 68 | 69 | // Instantiate MQTT 70 | setupMQTT(); 71 | 72 | setupAnimations(); 73 | 74 | } 75 | 76 | // Variables just for the example code below 77 | long lastWebRequest = -INFO_UPDATE_INTERVAL; 78 | 79 | void loop() { 80 | 81 | // All-purpose way to keep track of the time 82 | long now = millis(); 83 | 84 | // Loop our network services 85 | mqttLoop(); // Non-blocking MQTT connect/re-connect 86 | ArduinoOTA.handle(); // In case we want to upload a new sketch 87 | 88 | // Show tube stuff only if party mode is off 89 | if (party_mode == 0) { 90 | 91 | // We need to use the blocking fade because the 92 | // actual displaying of info is blocking too 93 | changeBrightnessBlocking(3000); 94 | 95 | // Only download new info every sp often, and don't bother if display is off 96 | if (now - lastWebRequest > INFO_UPDATE_INTERVAL && currentDisplayBrightness != 0) { 97 | 98 | downloadTubeInfo(); 99 | 100 | // Only display as offline if we've had 3 failed web requests in a row 101 | if (failed_attempts > 2) { 102 | displayOffline(); 103 | } else { 104 | displayTubeInfo(); 105 | } 106 | 107 | // Create a debug message 108 | lastWebRequest = now; 109 | 110 | } 111 | 112 | } else { 113 | 114 | // Use a non-blocking fade so the animation can continue 115 | // smoothly as we fade 116 | changeBrightnessNonBlocking(); 117 | 118 | // Draw the next frame of our patterns 119 | patternLoop(); 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/Geometry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d 6 | * Copyright (c) 2014 Noel Bundy 7 | * 8 | * Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/ 9 | * Copyright (c) 2008 Windell H Oskay. All right reserved. 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 12 | * this software and associated documentation files (the "Software"), to deal in 13 | * the Software without restriction, including without limitation the rights to 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15 | * the Software, and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 25 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef Geometry_H 30 | #define Geometry_H 31 | 32 | struct Vertex 33 | { 34 | float x, y, z; 35 | Vertex() 36 | { 37 | this->set(0, 0, 0); 38 | } 39 | 40 | Vertex(float x, float y, float z) 41 | { 42 | this->set(x, y, z); 43 | } 44 | 45 | void set(float x, float y, float z) 46 | { 47 | this->x = x; 48 | this->y = y; 49 | this->z = z; 50 | } 51 | }; 52 | 53 | struct EdgePoint 54 | { 55 | int x, y; 56 | boolean visible; 57 | 58 | EdgePoint() 59 | { 60 | this->set(0, 0); 61 | this->visible = false; 62 | } 63 | 64 | void set(int a, int b) 65 | { 66 | this->x = a; 67 | this->y = b; 68 | } 69 | }; 70 | 71 | struct Point 72 | { 73 | float x, y; 74 | 75 | Point() 76 | { 77 | set(0, 0); 78 | } 79 | 80 | Point(float x, float y) 81 | { 82 | set(x, y); 83 | } 84 | 85 | void set(float x, float y) 86 | { 87 | this->x = x; 88 | this->y = y; 89 | } 90 | 91 | }; 92 | 93 | struct squareFace 94 | { 95 | int length; 96 | int sommets[4]; 97 | int ed[4]; 98 | 99 | squareFace() 100 | { 101 | set(-1, -1, -1, -1); 102 | } 103 | 104 | squareFace(int a, int b, int c, int d) 105 | { 106 | this->length = 4; 107 | this->sommets[0] = a; 108 | this->sommets[1] = b; 109 | this->sommets[2] = c; 110 | this->sommets[3] = d; 111 | } 112 | 113 | void set(int a, int b, int c, int d) 114 | { 115 | this->length = 4; 116 | this->sommets[0] = a; 117 | this->sommets[1] = b; 118 | this->sommets[2] = c; 119 | this->sommets[3] = d; 120 | } 121 | 122 | }; 123 | 124 | struct triFace 125 | { 126 | int length; 127 | int sommets[3]; 128 | int ed[3]; 129 | 130 | triFace() 131 | { 132 | set(-1,-1,-1); 133 | } 134 | triFace(int a, int b, int c) 135 | { 136 | this->length =3; 137 | this->sommets[0]=a; 138 | this->sommets[1]=b; 139 | this->sommets[2]=c; 140 | } 141 | void set(int a, int b, int c) 142 | { 143 | this->length =3; 144 | this->sommets[0]=a; 145 | this->sommets[1]=b; 146 | this->sommets[2]=c; 147 | } 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/Geometry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d 6 | * Copyright (c) 2014 Noel Bundy 7 | * 8 | * Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/ 9 | * Copyright (c) 2008 Windell H Oskay. All right reserved. 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 12 | * this software and associated documentation files (the "Software"), to deal in 13 | * the Software without restriction, including without limitation the rights to 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15 | * the Software, and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 25 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef Geometry_H 30 | #define Geometry_H 31 | 32 | struct Vertex 33 | { 34 | float x, y, z; 35 | Vertex() 36 | { 37 | this->set(0, 0, 0); 38 | } 39 | 40 | Vertex(float x, float y, float z) 41 | { 42 | this->set(x, y, z); 43 | } 44 | 45 | void set(float x, float y, float z) 46 | { 47 | this->x = x; 48 | this->y = y; 49 | this->z = z; 50 | } 51 | }; 52 | 53 | struct EdgePoint 54 | { 55 | int x, y; 56 | boolean visible; 57 | 58 | EdgePoint() 59 | { 60 | this->set(0, 0); 61 | this->visible = false; 62 | } 63 | 64 | void set(int a, int b) 65 | { 66 | this->x = a; 67 | this->y = b; 68 | } 69 | }; 70 | 71 | struct Point 72 | { 73 | float x, y; 74 | 75 | Point() 76 | { 77 | set(0, 0); 78 | } 79 | 80 | Point(float x, float y) 81 | { 82 | set(x, y); 83 | } 84 | 85 | void set(float x, float y) 86 | { 87 | this->x = x; 88 | this->y = y; 89 | } 90 | 91 | }; 92 | 93 | struct squareFace 94 | { 95 | int length; 96 | int sommets[4]; 97 | int ed[4]; 98 | 99 | squareFace() 100 | { 101 | set(-1, -1, -1, -1); 102 | } 103 | 104 | squareFace(int a, int b, int c, int d) 105 | { 106 | this->length = 4; 107 | this->sommets[0] = a; 108 | this->sommets[1] = b; 109 | this->sommets[2] = c; 110 | this->sommets[3] = d; 111 | } 112 | 113 | void set(int a, int b, int c, int d) 114 | { 115 | this->length = 4; 116 | this->sommets[0] = a; 117 | this->sommets[1] = b; 118 | this->sommets[2] = c; 119 | this->sommets[3] = d; 120 | } 121 | 122 | }; 123 | 124 | struct triFace 125 | { 126 | int length; 127 | int sommets[3]; 128 | int ed[3]; 129 | 130 | triFace() 131 | { 132 | set(-1,-1,-1); 133 | } 134 | triFace(int a, int b, int c) 135 | { 136 | this->length =3; 137 | this->sommets[0]=a; 138 | this->sommets[1]=b; 139 | this->sommets[2]=c; 140 | } 141 | void set(int a, int b, int c) 142 | { 143 | this->length =3; 144 | this->sommets[0]=a; 145 | this->sommets[1]=b; 146 | this->sommets[2]=c; 147 | } 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/wifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | wifi.h 14 | * 15 | */ 16 | 17 | const unsigned long CONNECT_TIMEOUT = 30; // How long to attempt to connect to saved WiFi before going into AP mode 18 | const unsigned long AP_TIMEOUT = 60; // Wait 20 Seconds in the config portal before trying again the original WiFi creds 19 | 20 | // In case we want to do something when WiFiManager enters configuration mode 21 | void configModeCallback (WiFiManager *myWiFiManager) { 22 | Serial.println("[CALLBACK] configModeCallback fired"); 23 | display.setCursor(0,0); 24 | display.setBrightness(255); 25 | display.println("AP started..."); 26 | display.showBuffer(); 27 | } 28 | 29 | // In case we want to do something when the WiFi settings are saved 30 | void saveWifiCallback(){ 31 | Serial.println("[CALLBACK] saveCallback fired"); 32 | display.clearDisplay(); 33 | display.showBuffer(); 34 | } 35 | 36 | // To be called once in setup() 37 | // Just to make the main sketch cleaner 38 | void startWiFiManagerWithParameters() { 39 | 40 | // WiFiManager bits and pieces 41 | WiFiManager wm; 42 | wm.setSaveConfigCallback(saveConfigCallback); 43 | wm.setConnectTimeout(CONNECT_TIMEOUT); 44 | wm.setTimeout(AP_TIMEOUT); 45 | wm.setCountry("GB"); 46 | 47 | // Set hostname from settings 48 | wm.setHostname(hostname); 49 | 50 | // WiFiManager custom config 51 | WiFiManagerParameter custom_hostname("hostname", "Hostname", hostname, 24); 52 | WiFiManagerParameter custom_mqtt_server("server", "MQTT Server", mqtt_server, 40); 53 | WiFiManagerParameter custom_mqtt_port("port", "MQTT Port", mqtt_port, 6); 54 | WiFiManagerParameter custom_mqtt_username("username", "MQTT Username", mqtt_username, 32); 55 | WiFiManagerParameter custom_mqtt_password("password", "MQTT Password", mqtt_password, 32); 56 | WiFiManagerParameter custom_room("room", "Room Name", room, 30); 57 | WiFiManagerParameter custom_script_url("script_url", "Script URL", script_url, 50); 58 | wm.addParameter(&custom_hostname); 59 | wm.addParameter(&custom_room); 60 | wm.addParameter(&custom_mqtt_server); 61 | wm.addParameter(&custom_mqtt_port); 62 | wm.addParameter(&custom_mqtt_username); 63 | wm.addParameter(&custom_mqtt_password); 64 | wm.addParameter(&custom_script_url); 65 | 66 | //reset settings - wipe credentials for testing, if defined 67 | #if defined(START_ANEW) 68 | Serial.println("^^^^^^^^ Clearing WiFi credentials"); 69 | wm.resetSettings(); 70 | #endif 71 | 72 | // Run the routine to connect to the network 73 | if (!wm.autoConnect(hostname, "password")) { 74 | 75 | // If we've hit the config portal timeout, then retstart 76 | 77 | Serial.println("%%% Failed to connect and hit timeout, restarting"); 78 | delay(100); 79 | ESP.restart(); 80 | 81 | // Not sure if this line is necessary 82 | delay(5000); 83 | } 84 | 85 | // Keeping this line cos it's cute 86 | Serial.println("Connected ...yeey :)"); 87 | 88 | // Update parameters from the new values set in the portal 89 | strcpy(hostname, custom_hostname.getValue()); 90 | strcpy(room, custom_room.getValue()); 91 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 92 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 93 | strcpy(mqtt_username, custom_mqtt_username.getValue()); 94 | strcpy(mqtt_password, custom_mqtt_password.getValue()); 95 | strcpy(script_url, custom_script_url.getValue()); 96 | 97 | if (shouldSaveConfig) { 98 | saveConfig(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/Geometry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d 6 | * Copyright (c) 2014 Noel Bundy 7 | * 8 | * Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/ 9 | * Copyright (c) 2008 Windell H Oskay. All right reserved. 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 12 | * this software and associated documentation files (the "Software"), to deal in 13 | * the Software without restriction, including without limitation the rights to 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15 | * the Software, and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 25 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef Geometry_H 30 | #define Geometry_H 31 | 32 | struct Vertex 33 | { 34 | float x, y, z; 35 | Vertex() 36 | { 37 | this->set(0, 0, 0); 38 | } 39 | 40 | Vertex(float x, float y, float z) 41 | { 42 | this->set(x, y, z); 43 | } 44 | 45 | void set(float x, float y, float z) 46 | { 47 | this->x = x; 48 | this->y = y; 49 | this->z = z; 50 | } 51 | }; 52 | 53 | struct EdgePoint 54 | { 55 | int x, y; 56 | boolean visible; 57 | 58 | EdgePoint() 59 | { 60 | this->set(0, 0); 61 | this->visible = false; 62 | } 63 | 64 | void set(int a, int b) 65 | { 66 | this->x = a; 67 | this->y = b; 68 | } 69 | }; 70 | 71 | struct Point 72 | { 73 | float x, y; 74 | 75 | Point() 76 | { 77 | set(0, 0); 78 | } 79 | 80 | Point(float x, float y) 81 | { 82 | set(x, y); 83 | } 84 | 85 | void set(float x, float y) 86 | { 87 | this->x = x; 88 | this->y = y; 89 | } 90 | 91 | }; 92 | 93 | struct squareFace 94 | { 95 | int length; 96 | int sommets[4]; 97 | int ed[4]; 98 | 99 | squareFace() 100 | { 101 | set(-1, -1, -1, -1); 102 | } 103 | 104 | squareFace(int a, int b, int c, int d) 105 | { 106 | this->length = 4; 107 | this->sommets[0] = a; 108 | this->sommets[1] = b; 109 | this->sommets[2] = c; 110 | this->sommets[3] = d; 111 | } 112 | 113 | void set(int a, int b, int c, int d) 114 | { 115 | this->length = 4; 116 | this->sommets[0] = a; 117 | this->sommets[1] = b; 118 | this->sommets[2] = c; 119 | this->sommets[3] = d; 120 | } 121 | 122 | }; 123 | 124 | struct triFace 125 | { 126 | int length; 127 | int sommets[3]; 128 | int ed[3]; 129 | 130 | triFace() 131 | { 132 | set(-1,-1,-1); 133 | } 134 | triFace(int a, int b, int c) 135 | { 136 | this->length =3; 137 | this->sommets[0]=a; 138 | this->sommets[1]=b; 139 | this->sommets[2]=c; 140 | } 141 | void set(int a, int b, int c) 142 | { 143 | this->length =3; 144 | this->sommets[0]=a; 145 | this->sommets[1]=b; 146 | this->sommets[2]=c; 147 | } 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/wifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | wifi.h 14 | * 15 | */ 16 | 17 | const unsigned long CONNECT_TIMEOUT = 30; // How long to attempt to connect to saved WiFi before going into AP mode 18 | const unsigned long AP_TIMEOUT = 60; // Wait 20 Seconds in the config portal before trying again the original WiFi creds 19 | 20 | // In case we want to do something when WiFiManager enters configuration mode 21 | void configModeCallback (WiFiManager *myWiFiManager) { 22 | Serial.println("[CALLBACK] configModeCallback fired"); 23 | display.setCursor(0,0); 24 | display.setBrightness(255); 25 | display.println("AP started..."); 26 | display.showBuffer(); 27 | } 28 | 29 | // In case we want to do something when the WiFi settings are saved 30 | void saveWifiCallback(){ 31 | Serial.println("[CALLBACK] saveCallback fired"); 32 | display.clearDisplay(); 33 | display.showBuffer(); 34 | } 35 | 36 | // To be called once in setup() 37 | // Just to make the main sketch cleaner 38 | void startWiFiManagerWithParameters() { 39 | 40 | // WiFiManager bits and pieces 41 | WiFiManager wm; 42 | wm.setSaveConfigCallback(saveConfigCallback); 43 | wm.setConnectTimeout(CONNECT_TIMEOUT); 44 | wm.setTimeout(AP_TIMEOUT); 45 | wm.setCountry("GB"); 46 | 47 | // Set hostname from settings 48 | wm.setHostname(hostname); 49 | 50 | // WiFiManager custom config 51 | WiFiManagerParameter custom_hostname("hostname", "Hostname", hostname, 24); 52 | WiFiManagerParameter custom_mqtt_server("server", "MQTT Server", mqtt_server, 40); 53 | WiFiManagerParameter custom_mqtt_port("port", "MQTT Port", mqtt_port, 6); 54 | WiFiManagerParameter custom_mqtt_username("username", "MQTT Username", mqtt_username, 32); 55 | WiFiManagerParameter custom_mqtt_password("password", "MQTT Password", mqtt_password, 32); 56 | WiFiManagerParameter custom_room("room", "Room Name", room, 30); 57 | WiFiManagerParameter custom_flight_area("flight_area", "Long/Lat Bounds", flight_area, 36); 58 | wm.addParameter(&custom_hostname); 59 | wm.addParameter(&custom_room); 60 | wm.addParameter(&custom_mqtt_server); 61 | wm.addParameter(&custom_mqtt_port); 62 | wm.addParameter(&custom_mqtt_username); 63 | wm.addParameter(&custom_mqtt_password); 64 | wm.addParameter(&custom_flight_area); 65 | 66 | //reset settings - wipe credentials for testing, if defined 67 | #if defined(START_ANEW) 68 | Serial.println("^^^^^^^^ Clearing WiFi credentials"); 69 | wm.resetSettings(); 70 | #endif 71 | 72 | // Run the routine to connect to the network 73 | if (!wm.autoConnect(hostname, "password")) { 74 | 75 | // If we've hit the config portal timeout, then retstart 76 | 77 | Serial.println("%%% Failed to connect and hit timeout, restarting"); 78 | delay(100); 79 | ESP.restart(); 80 | 81 | // Not sure if this line is necessary 82 | delay(5000); 83 | } 84 | 85 | // Keeping this line cos it's cute 86 | Serial.println("Connected ...yeey :)"); 87 | 88 | // Update parameters from the new values set in the portal 89 | strcpy(hostname, custom_hostname.getValue()); 90 | strcpy(room, custom_room.getValue()); 91 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 92 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 93 | strcpy(mqtt_username, custom_mqtt_username.getValue()); 94 | strcpy(mqtt_password, custom_mqtt_password.getValue()); 95 | strcpy(flight_area, custom_flight_area.getValue()); 96 | 97 | if (shouldSaveConfig) { 98 | saveConfig(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/wifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | wifi.h 14 | * 15 | */ 16 | 17 | const unsigned long CONNECT_TIMEOUT = 30; // How long to attempt to connect to saved WiFi before going into AP mode 18 | const unsigned long AP_TIMEOUT = 60; // Wait 20 Seconds in the config portal before trying again the original WiFi creds 19 | 20 | // In case we want to do something when WiFiManager enters configuration mode 21 | void configModeCallback (WiFiManager *myWiFiManager) { 22 | Serial.println("[CALLBACK] configModeCallback fired"); 23 | display.setCursor(0,0); 24 | display.setBrightness(255); 25 | display.println("AP started..."); 26 | display.showBuffer(); 27 | } 28 | 29 | // In case we want to do something when the WiFi settings are saved 30 | void saveWifiCallback(){ 31 | Serial.println("[CALLBACK] saveCallback fired"); 32 | display.clearDisplay(); 33 | display.showBuffer(); 34 | } 35 | 36 | // To be called once in setup() 37 | // Just to make the main sketch cleaner 38 | void startWiFiManagerWithParameters() { 39 | 40 | // WiFiManager bits and pieces 41 | WiFiManager wm; 42 | wm.setSaveConfigCallback(saveConfigCallback); 43 | wm.setConnectTimeout(CONNECT_TIMEOUT); 44 | wm.setTimeout(AP_TIMEOUT); 45 | wm.setCountry("GB"); 46 | 47 | // Set hostname from settings 48 | wm.setHostname(hostname); 49 | 50 | // WiFiManager custom config 51 | WiFiManagerParameter custom_hostname("hostname", "Hostname", hostname, 24); 52 | WiFiManagerParameter custom_mqtt_server("server", "MQTT Server", mqtt_server, 40); 53 | WiFiManagerParameter custom_mqtt_port("port", "MQTT Port", mqtt_port, 6); 54 | WiFiManagerParameter custom_mqtt_username("username", "MQTT Username", mqtt_username, 32); 55 | WiFiManagerParameter custom_mqtt_password("password", "MQTT Password", mqtt_password, 32); 56 | WiFiManagerParameter custom_room("room", "Room Name", room, 30); 57 | WiFiManagerParameter custom_tfl_station_id("station_id", "TfL Station ID", tfl_station_id, 24); 58 | WiFiManagerParameter custom_tfl_route("route", "TfL Route (circle, H91)", tfl_route, 24); 59 | WiFiManagerParameter custom_tfl_direction("direction", "TfL Direction (inbound, outbound, empty)", tfl_direction, 24); 60 | wm.addParameter(&custom_hostname); 61 | wm.addParameter(&custom_room); 62 | wm.addParameter(&custom_mqtt_server); 63 | wm.addParameter(&custom_mqtt_port); 64 | wm.addParameter(&custom_mqtt_username); 65 | wm.addParameter(&custom_mqtt_password); 66 | wm.addParameter(&custom_tfl_station_id); 67 | wm.addParameter(&custom_tfl_route); 68 | wm.addParameter(&custom_tfl_direction); 69 | 70 | //reset settings - wipe credentials for testing, if defined 71 | #if defined(START_ANEW) 72 | Serial.println("^^^^^^^^ Clearing WiFi credentials"); 73 | wm.resetSettings(); 74 | #endif 75 | 76 | // Run the routine to connect to the network 77 | if (!wm.autoConnect(hostname, "password")) { 78 | 79 | // If we've hit the config portal timeout, then retstart 80 | 81 | Serial.println("%%% Failed to connect and hit timeout, restarting"); 82 | delay(100); 83 | ESP.restart(); 84 | 85 | // Not sure if this line is necessary 86 | delay(5000); 87 | } 88 | 89 | // Keeping this line cos it's cute 90 | Serial.println("Connected ...yeey :)"); 91 | 92 | // Update parameters from the new values set in the portal 93 | strcpy(hostname, custom_hostname.getValue()); 94 | strcpy(room, custom_room.getValue()); 95 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 96 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 97 | strcpy(mqtt_username, custom_mqtt_username.getValue()); 98 | strcpy(mqtt_password, custom_mqtt_password.getValue()); 99 | 100 | if (shouldSaveConfig) { 101 | saveConfig(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | // Default values for config common to all projects 18 | char hostname[24] = "glowingsquare_unifi"; 19 | char script_url[50] = "http://10.0.1.145:8080/"; 20 | char room[30] = "living_room"; 21 | char mqtt_server[40]; 22 | char mqtt_port[6] = "1883"; 23 | char mqtt_username[40]; 24 | char mqtt_password[40]; 25 | 26 | // Default custom static IP (not always used) 27 | char static_ip[16] = "10.0.3.255"; 28 | char static_gw[16] = "10.0.1.1"; 29 | char static_sn[16] = "255.255.0.0"; 30 | 31 | //flag for saving data 32 | bool shouldSaveConfig = false; 33 | 34 | //callback notifying us of the need to save config 35 | void saveConfigCallback () { 36 | Serial.println("Should save config"); 37 | shouldSaveConfig = true; 38 | } 39 | 40 | void setupStorage(){ 41 | //clean FS, for testing, if flag enabled 42 | #if defined(START_ANEW) 43 | Serial.println("^^^^^^^^ Clearing SPIFFS"); 44 | SPIFFS.format(); 45 | #endif 46 | 47 | //read configuration from FS json 48 | Serial.println("mounting FS..."); 49 | 50 | if (SPIFFS.begin()) { 51 | Serial.println("mounted file system"); 52 | if (SPIFFS.exists("/config.json")) { 53 | //file exists, reading and loading 54 | Serial.println("reading config file"); 55 | File configFile = SPIFFS.open("/config.json", "r"); 56 | if (configFile) { 57 | Serial.println("opened config file"); 58 | size_t size = configFile.size(); 59 | // Allocate a buffer to store contents of the file. 60 | std::unique_ptr buf(new char[size]); 61 | 62 | configFile.readBytes(buf.get(), size); 63 | StaticJsonDocument<256> json; 64 | DeserializationError jsonError = deserializeJson(json, buf.get()); 65 | 66 | serializeJsonPretty(json, Serial); 67 | if (!jsonError) { 68 | Serial.println("\nparsed json"); 69 | 70 | strcpy(hostname, json["hostname"]); 71 | strcpy(room, json["room"]); 72 | strcpy(mqtt_server, json["mqtt_server"]); 73 | strcpy(mqtt_port, json["mqtt_port"]); 74 | strcpy(mqtt_username, json["mqtt_username"]); 75 | strcpy(mqtt_password, json["mqtt_password"]); 76 | strcpy(script_url, json["script_url"]); 77 | 78 | 79 | // if(json["ip"]) { 80 | // Serial.println("setting custom ip from config"); 81 | // strcpy(static_ip, json["ip"]); 82 | // strcpy(static_gw, json["gateway"]); 83 | // strcpy(static_sn, json["subnet"]); 84 | // Serial.println(static_ip); 85 | // } else { 86 | // Serial.println("no custom ip in config"); 87 | // } 88 | 89 | } else { 90 | Serial.println("failed to load json config"); 91 | } 92 | } 93 | } 94 | } else { 95 | Serial.println("failed to mount FS"); 96 | } 97 | //end read 98 | } 99 | 100 | void saveConfig() { 101 | Serial.println("saving config"); 102 | 103 | StaticJsonDocument<256> json; 104 | json["mqtt_server"] = mqtt_server; 105 | json["mqtt_port"] = mqtt_port; 106 | json["mqtt_username"] = mqtt_username; 107 | json["mqtt_password"] = mqtt_password; 108 | json["hostname"] = hostname; 109 | json["room"] = room; 110 | json["script_url"] = script_url; 111 | 112 | // json["ip"] = WiFi.localIP().toString(); 113 | // json["gateway"] = WiFi.gatewayIP().toString(); 114 | // json["subnet"] = WiFi.subnetMask().toString(); 115 | 116 | File configFile = SPIFFS.open("/config.json", "w"); 117 | if (!configFile) { 118 | Serial.println("failed to open config file for writing"); 119 | } 120 | 121 | serializeJsonPretty(json, Serial); 122 | 123 | serializeJson(json, configFile); 124 | configFile.close(); 125 | //end save 126 | shouldSaveConfig = false; 127 | } 128 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | // Default values for config common to all projects 18 | char hostname[24] = "glowingsquare_flight"; 19 | char room[30] = "living_room"; 20 | char mqtt_server[40]; 21 | char mqtt_port[6] = "1883"; 22 | char mqtt_username[40]; 23 | char mqtt_password[40]; 24 | char flight_area[36] = "51.5672,51.4131,-0.4146,0.1107"; 25 | 26 | // Default custom static IP (not always used) 27 | char static_ip[16] = "10.0.3.255"; 28 | char static_gw[16] = "10.0.1.1"; 29 | char static_sn[16] = "255.255.0.0"; 30 | 31 | //flag for saving data 32 | bool shouldSaveConfig = false; 33 | 34 | //callback notifying us of the need to save config 35 | void saveConfigCallback () { 36 | Serial.println("Should save config"); 37 | shouldSaveConfig = true; 38 | } 39 | 40 | void setupStorage(){ 41 | //clean FS, for testing, if flag enabled 42 | #if defined(START_ANEW) 43 | Serial.println("^^^^^^^^ Clearing SPIFFS"); 44 | SPIFFS.format(); 45 | #endif 46 | 47 | //read configuration from FS json 48 | Serial.println("mounting FS..."); 49 | 50 | if (SPIFFS.begin()) { 51 | Serial.println("mounted file system"); 52 | if (SPIFFS.exists("/config.json")) { 53 | //file exists, reading and loading 54 | Serial.println("reading config file"); 55 | File configFile = SPIFFS.open("/config.json", "r"); 56 | if (configFile) { 57 | Serial.println("opened config file"); 58 | size_t size = configFile.size(); 59 | // Allocate a buffer to store contents of the file. 60 | std::unique_ptr buf(new char[size]); 61 | 62 | configFile.readBytes(buf.get(), size); 63 | StaticJsonDocument<256> json; 64 | DeserializationError jsonError = deserializeJson(json, buf.get()); 65 | 66 | serializeJsonPretty(json, Serial); 67 | if (!jsonError) { 68 | Serial.println("\nparsed json"); 69 | 70 | strcpy(hostname, json["hostname"]); 71 | strcpy(room, json["room"]); 72 | strcpy(mqtt_server, json["mqtt_server"]); 73 | strcpy(mqtt_port, json["mqtt_port"]); 74 | strcpy(mqtt_username, json["mqtt_username"]); 75 | strcpy(mqtt_password, json["mqtt_password"]); 76 | strcpy(flight_area, json["flight_area"]); 77 | 78 | 79 | // if(json["ip"]) { 80 | // Serial.println("setting custom ip from config"); 81 | // strcpy(static_ip, json["ip"]); 82 | // strcpy(static_gw, json["gateway"]); 83 | // strcpy(static_sn, json["subnet"]); 84 | // Serial.println(static_ip); 85 | // } else { 86 | // Serial.println("no custom ip in config"); 87 | // } 88 | 89 | } else { 90 | Serial.println("failed to load json config"); 91 | } 92 | } 93 | } 94 | } else { 95 | Serial.println("failed to mount FS"); 96 | } 97 | //end read 98 | } 99 | 100 | void saveConfig() { 101 | Serial.println("saving config"); 102 | 103 | StaticJsonDocument<256> json; 104 | json["mqtt_server"] = mqtt_server; 105 | json["mqtt_port"] = mqtt_port; 106 | json["mqtt_username"] = mqtt_username; 107 | json["mqtt_password"] = mqtt_password; 108 | json["hostname"] = hostname; 109 | json["room"] = room; 110 | json["flight_area"] = flight_area; 111 | 112 | // json["ip"] = WiFi.localIP().toString(); 113 | // json["gateway"] = WiFi.gatewayIP().toString(); 114 | // json["subnet"] = WiFi.subnetMask().toString(); 115 | 116 | File configFile = SPIFFS.open("/config.json", "w"); 117 | if (!configFile) { 118 | Serial.println("failed to open config file for writing"); 119 | } 120 | 121 | serializeJsonPretty(json, Serial); 122 | 123 | serializeJson(json, configFile); 124 | configFile.close(); 125 | //end save 126 | shouldSaveConfig = false; 127 | } 128 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/web/index.php: -------------------------------------------------------------------------------- 1 | < | | | (_) | | | __/ |_| | 10 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 11 | __/ | 12 | Glowing Square: Unifi Display |___/ 13 | For PHP web server 14 | index.php 15 | * 16 | */ 17 | 18 | require_once('config.php'); 19 | require_once('UnifiClient.php'); 20 | 21 | function formatBytes($bytes, $precision = 2) { 22 | 23 | // Round to the nearest byte 24 | $bytes = round($bytes, 0); 25 | 26 | $units = array('B', 'KB', 'MB', 'GB', 'TB'); 27 | $short_units = array('B', 'K', 'M', 'G', 'T'); 28 | 29 | // Don't allow minus bytes 30 | $bytes = max($bytes, 0); 31 | $pow = floor(($bytes ? log($bytes) : 0) / log(1000)); 32 | $pow = min($pow, count($units) - 1); 33 | 34 | // Adjust the bytes to MB, GB, etc 35 | $bytes /= pow(1000, $pow); 36 | 37 | // If we're using TB then allow for one more DP 38 | if ($pow == 4) $precision += 1; 39 | 40 | // Format it to the correct dp 41 | $number = number_format($bytes, $precision); 42 | 43 | if (strlen($number) > 2) { 44 | return $number . $short_units[$pow]; 45 | } else { 46 | return $number . $units[$pow]; 47 | } 48 | 49 | } 50 | 51 | /** 52 | * initialize the UniFi API connection class and log in to the controller and pull the requested data 53 | */ 54 | $unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); 55 | $set_debug_mode = $unifi_connection->set_debug($debug); 56 | $loginresults = $unifi_connection->login(); 57 | $clients = $unifi_connection->list_clients(); 58 | $minute_stats = $unifi_connection->stat_5minutes_site(); 59 | $daily_stats = $unifi_connection->stat_daily_site(); 60 | 61 | $out = []; 62 | 63 | /* 64 | Client Stats 65 | */ 66 | $out['clients'] = 0; 67 | $out['guests'] = 0; 68 | $out['wireless'] = 0; 69 | $out['wired'] = 0; 70 | $raw_month_tx = 0; 71 | $raw_month_rx = 0; 72 | $out['min_uptime'] = 9999999999; 73 | 74 | // Count the different types of clients 75 | foreach ($clients as $client) { 76 | 77 | if ($client->is_guest) $out['guests']++; 78 | else $out['clients']++; 79 | 80 | if ($client->is_wired) $out['wired']++; 81 | else $out['wireless']++; 82 | 83 | if ($client->uptime < $out['min_uptime']) { 84 | $out['newest'] = $client->hostname; 85 | $out['min_uptime'] = $client->uptime; 86 | } 87 | 88 | } 89 | 90 | /* 91 | Monthly Stats 92 | */ 93 | 94 | // Gather the monthly totals of WAN up and down 95 | $current_month = date('m', time()); 96 | 97 | foreach ($daily_stats as $stat) { 98 | 99 | // The time is provided in ms, annoyingly 100 | $time = $stat->time / 1000; 101 | 102 | // Only use the data if it's from this month 103 | if (date('m', $time) == $current_month) { 104 | $raw_month_tx += $stat->{'wan-tx_bytes'}; 105 | $raw_month_rx += $stat->{'wan-rx_bytes'}; 106 | } 107 | 108 | } 109 | 110 | // Format the byte counts into something more readable 111 | $out['month_tx'] = formatBytes($raw_month_tx, 0); 112 | $out['month_rx'] = formatBytes($raw_month_rx, 0); 113 | 114 | /* 115 | Minute-by-minute graph 116 | */ 117 | $out['graph'] = []; 118 | // Each entry will be one line of pixels on the graph 119 | // So we only want the last 64 entries 120 | $graph_width = $_GET['width']; 121 | $graph_height = $_GET['height']; 122 | 123 | // Use the last 100 datapoints to figure out the max height of the graph 124 | $n = 100; 125 | foreach (array_slice($minute_stats, -$n, $n) as $stat) { 126 | 127 | // Define what we're using for the graph 128 | $bytes = $stat->{'wan-rx_bytes'}; 129 | 130 | if ($bytes > $max_graph) $max_graph = $bytes; 131 | } 132 | 133 | // Use the display width number of datapoints to draw the graph 134 | 135 | foreach (array_slice($minute_stats, -$graph_width, $graph_width) as $stat) { 136 | 137 | // Define what we're using for the graph 138 | $bytes = $stat->{'wan-rx_bytes'}; 139 | 140 | $pixel_height = ceil(($bytes/ $max_graph) * $graph_height); 141 | array_push($out['graph'], $pixel_height); 142 | 143 | } 144 | 145 | /* 146 | Output the data with the correct headers 147 | */ 148 | header('Content-Type: application/json; charset=utf-8'); 149 | echo json_encode($out); 150 | 151 | ?> 152 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/PatternWave.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternWave_H 24 | #define PatternWave_H 25 | 26 | class PatternWave : public Drawable { 27 | private: 28 | byte thetaUpdate = 0; 29 | byte thetaUpdateFrequency = 0; 30 | byte theta = 0; 31 | 32 | byte hueUpdate = 0; 33 | byte hueUpdateFrequency = 0; 34 | byte hue = 0; 35 | 36 | byte rotation = 0; 37 | 38 | uint8_t scale = 256 / MATRIX_WIDTH; 39 | 40 | uint8_t maxX = MATRIX_WIDTH - 1; 41 | uint8_t maxY = MATRIX_HEIGHT - 1; 42 | 43 | uint8_t waveCount = 1; 44 | 45 | public: 46 | PatternWave() { 47 | name = (char *)"Wave"; 48 | } 49 | 50 | void start() { 51 | rotation = random(0, 4); 52 | waveCount = random(1, 3); 53 | 54 | } 55 | 56 | unsigned int drawFrame() { 57 | int n = 0; 58 | 59 | switch (rotation) { 60 | case 0: 61 | for (int x = 0; x < MATRIX_WIDTH; x++) { 62 | n = quadwave8(x * 2 + theta) / scale; 63 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 64 | if (waveCount == 2) 65 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 66 | } 67 | break; 68 | 69 | case 1: 70 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 71 | n = quadwave8(y * 2 + theta) / scale; 72 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 73 | if (waveCount == 2) 74 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 75 | } 76 | break; 77 | 78 | case 2: 79 | for (int x = 0; x < MATRIX_WIDTH; x++) { 80 | n = quadwave8(x * 2 - theta) / scale; 81 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 82 | if (waveCount == 2) 83 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 84 | } 85 | break; 86 | 87 | case 3: 88 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 89 | n = quadwave8(y * 2 - theta) / scale; 90 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 91 | if (waveCount == 2) 92 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 93 | } 94 | break; 95 | } 96 | 97 | effects.DimAll(254); 98 | effects.ShowFrame(); 99 | 100 | if (thetaUpdate >= thetaUpdateFrequency) { 101 | thetaUpdate = 0; 102 | theta++; 103 | } 104 | else { 105 | thetaUpdate++; 106 | } 107 | 108 | if (hueUpdate >= hueUpdateFrequency) { 109 | hueUpdate = 0; 110 | hue++; 111 | } 112 | else { 113 | hueUpdate++; 114 | } 115 | 116 | return 0; 117 | } 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/PatternWave.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternWave_H 24 | #define PatternWave_H 25 | 26 | class PatternWave : public Drawable { 27 | private: 28 | byte thetaUpdate = 0; 29 | byte thetaUpdateFrequency = 0; 30 | byte theta = 0; 31 | 32 | byte hueUpdate = 0; 33 | byte hueUpdateFrequency = 0; 34 | byte hue = 0; 35 | 36 | byte rotation = 0; 37 | 38 | uint8_t scale = 256 / MATRIX_WIDTH; 39 | 40 | uint8_t maxX = MATRIX_WIDTH - 1; 41 | uint8_t maxY = MATRIX_HEIGHT - 1; 42 | 43 | uint8_t waveCount = 1; 44 | 45 | public: 46 | PatternWave() { 47 | name = (char *)"Wave"; 48 | } 49 | 50 | void start() { 51 | rotation = random(0, 4); 52 | waveCount = random(1, 3); 53 | 54 | } 55 | 56 | unsigned int drawFrame() { 57 | int n = 0; 58 | 59 | switch (rotation) { 60 | case 0: 61 | for (int x = 0; x < MATRIX_WIDTH; x++) { 62 | n = quadwave8(x * 2 + theta) / scale; 63 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 64 | if (waveCount == 2) 65 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 66 | } 67 | break; 68 | 69 | case 1: 70 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 71 | n = quadwave8(y * 2 + theta) / scale; 72 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 73 | if (waveCount == 2) 74 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 75 | } 76 | break; 77 | 78 | case 2: 79 | for (int x = 0; x < MATRIX_WIDTH; x++) { 80 | n = quadwave8(x * 2 - theta) / scale; 81 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 82 | if (waveCount == 2) 83 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 84 | } 85 | break; 86 | 87 | case 3: 88 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 89 | n = quadwave8(y * 2 - theta) / scale; 90 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 91 | if (waveCount == 2) 92 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 93 | } 94 | break; 95 | } 96 | 97 | effects.DimAll(254); 98 | effects.ShowFrame(); 99 | 100 | if (thetaUpdate >= thetaUpdateFrequency) { 101 | thetaUpdate = 0; 102 | theta++; 103 | } 104 | else { 105 | thetaUpdate++; 106 | } 107 | 108 | if (hueUpdate >= hueUpdateFrequency) { 109 | hueUpdate = 0; 110 | hue++; 111 | } 112 | else { 113 | hueUpdate++; 114 | } 115 | 116 | return 0; 117 | } 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/PatternWave.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternWave_H 24 | #define PatternWave_H 25 | 26 | class PatternWave : public Drawable { 27 | private: 28 | byte thetaUpdate = 0; 29 | byte thetaUpdateFrequency = 0; 30 | byte theta = 0; 31 | 32 | byte hueUpdate = 0; 33 | byte hueUpdateFrequency = 0; 34 | byte hue = 0; 35 | 36 | byte rotation = 0; 37 | 38 | uint8_t scale = 256 / MATRIX_WIDTH; 39 | 40 | uint8_t maxX = MATRIX_WIDTH - 1; 41 | uint8_t maxY = MATRIX_HEIGHT - 1; 42 | 43 | uint8_t waveCount = 1; 44 | 45 | public: 46 | PatternWave() { 47 | name = (char *)"Wave"; 48 | } 49 | 50 | void start() { 51 | rotation = random(0, 4); 52 | waveCount = random(1, 3); 53 | 54 | } 55 | 56 | unsigned int drawFrame() { 57 | int n = 0; 58 | 59 | switch (rotation) { 60 | case 0: 61 | for (int x = 0; x < MATRIX_WIDTH; x++) { 62 | n = quadwave8(x * 2 + theta) / scale; 63 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 64 | if (waveCount == 2) 65 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 66 | } 67 | break; 68 | 69 | case 1: 70 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 71 | n = quadwave8(y * 2 + theta) / scale; 72 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 73 | if (waveCount == 2) 74 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 75 | } 76 | break; 77 | 78 | case 2: 79 | for (int x = 0; x < MATRIX_WIDTH; x++) { 80 | n = quadwave8(x * 2 - theta) / scale; 81 | effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue)); 82 | if (waveCount == 2) 83 | effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 84 | } 85 | break; 86 | 87 | case 3: 88 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 89 | n = quadwave8(y * 2 - theta) / scale; 90 | effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue)); 91 | if (waveCount == 2) 92 | effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 93 | } 94 | break; 95 | } 96 | 97 | effects.DimAll(254); 98 | effects.ShowFrame(); 99 | 100 | if (thetaUpdate >= thetaUpdateFrequency) { 101 | thetaUpdate = 0; 102 | theta++; 103 | } 104 | else { 105 | thetaUpdate++; 106 | } 107 | 108 | if (hueUpdate >= hueUpdateFrequency) { 109 | hueUpdate = 0; 110 | hue++; 111 | } 112 | else { 113 | hueUpdate++; 114 | } 115 | 116 | return 0; 117 | } 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | // Default values for config common to all projects 18 | char hostname[24] = "glowingsquare_tube"; 19 | char mqtt_server[40]; 20 | char mqtt_port[6] = "1883"; 21 | char mqtt_username[40]; 22 | char mqtt_password[40]; 23 | char room[30] = "living_room"; 24 | char tfl_station_id[24] = "940GZZLUACY"; 25 | char tfl_route[24] = "northern"; 26 | char tfl_direction[8] = "inbound"; 27 | 28 | // Default custom static IP (not always used) 29 | char static_ip[16] = "10.0.3.255"; 30 | char static_gw[16] = "10.0.1.1"; 31 | char static_sn[16] = "255.255.0.0"; 32 | 33 | //flag for saving data 34 | bool shouldSaveConfig = false; 35 | 36 | //callback notifying us of the need to save config 37 | void saveConfigCallback () { 38 | Serial.println("Should save config"); 39 | shouldSaveConfig = true; 40 | } 41 | 42 | void setupStorage(){ 43 | //clean FS, for testing, if flag enabled 44 | #if defined(START_ANEW) 45 | Serial.println("^^^^^^^^ Clearing SPIFFS"); 46 | SPIFFS.format(); 47 | #endif 48 | 49 | //read configuration from FS json 50 | Serial.println("mounting FS..."); 51 | 52 | if (SPIFFS.begin()) { 53 | Serial.println("mounted file system"); 54 | if (SPIFFS.exists("/config.json")) { 55 | //file exists, reading and loading 56 | Serial.println("reading config file"); 57 | File configFile = SPIFFS.open("/config.json", "r"); 58 | if (configFile) { 59 | Serial.println("opened config file"); 60 | size_t size = configFile.size(); 61 | // Allocate a buffer to store contents of the file. 62 | std::unique_ptr buf(new char[size]); 63 | 64 | configFile.readBytes(buf.get(), size); 65 | StaticJsonDocument<256> json; 66 | DeserializationError jsonError = deserializeJson(json, buf.get()); 67 | 68 | serializeJsonPretty(json, Serial); 69 | if (!jsonError) { 70 | Serial.println("\nparsed json"); 71 | 72 | strcpy(hostname, json["hostname"]); 73 | strcpy(mqtt_server, json["mqtt_server"]); 74 | strcpy(mqtt_port, json["mqtt_port"]); 75 | strcpy(mqtt_username, json["mqtt_username"]); 76 | strcpy(mqtt_password, json["mqtt_password"]); 77 | strcpy(room, json["room"]); 78 | strcpy(tfl_station_id, json["tfl_station_id"]); 79 | strcpy(tfl_route, json["tfl_route"]); 80 | strcpy(tfl_direction, json["tfl_direction"]); 81 | 82 | 83 | // if(json["ip"]) { 84 | // Serial.println("setting custom ip from config"); 85 | // strcpy(static_ip, json["ip"]); 86 | // strcpy(static_gw, json["gateway"]); 87 | // strcpy(static_sn, json["subnet"]); 88 | // Serial.println(static_ip); 89 | // } else { 90 | // Serial.println("no custom ip in config"); 91 | // } 92 | 93 | } else { 94 | Serial.println("failed to load json config"); 95 | } 96 | } 97 | } 98 | } else { 99 | Serial.println("failed to mount FS"); 100 | } 101 | //end read 102 | } 103 | 104 | void saveConfig() { 105 | Serial.println("saving config"); 106 | 107 | StaticJsonDocument<256> json; 108 | json["mqtt_server"] = mqtt_server; 109 | json["mqtt_port"] = mqtt_port; 110 | json["mqtt_username"] = mqtt_username; 111 | json["mqtt_password"] = mqtt_password; 112 | json["hostname"] = hostname; 113 | json["room"] = room; 114 | json["tfl_station_id"] = tfl_station_id; 115 | json["tfl_route"] = tfl_route; 116 | json["tfl_direction"] = tfl_direction; 117 | 118 | // json["ip"] = WiFi.localIP().toString(); 119 | // json["gateway"] = WiFi.gatewayIP().toString(); 120 | // json["subnet"] = WiFi.subnetMask().toString(); 121 | 122 | File configFile = SPIFFS.open("/config.json", "w"); 123 | if (!configFile) { 124 | Serial.println("failed to open config file for writing"); 125 | } 126 | 127 | serializeJsonPretty(json, Serial); 128 | 129 | serializeJson(json, configFile); 130 | configFile.close(); 131 | //end save 132 | shouldSaveConfig = false; 133 | } 134 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/PatternFlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | // Flocking 28 | // Daniel Shiffman 29 | // The Nature of Code, Spring 2009 30 | 31 | // Demonstration of Craig Reynolds' "Flocking" behavior 32 | // See: http://www.red3d.com/cwr/ 33 | // Rules: Cohesion, Separation, Alignment 34 | 35 | #ifndef PatternFlock_H 36 | #define PatternFlock_H 37 | 38 | class PatternFlock : public Drawable { 39 | public: 40 | PatternFlock() { 41 | name = (char *)"Flock"; 42 | } 43 | 44 | static const int boidCount = 10; 45 | Boid predator; 46 | 47 | PVector wind; 48 | byte hue = 0; 49 | bool predatorPresent = true; 50 | 51 | void start() { 52 | for (int i = 0; i < boidCount; i++) { 53 | boids[i] = Boid(15, 15); 54 | boids[i].maxspeed = 0.380; 55 | boids[i].maxforce = 0.015; 56 | } 57 | 58 | predatorPresent = random(0, 2) >= 1; 59 | if (predatorPresent) { 60 | predator = Boid(31, 31); 61 | predatorPresent = true; 62 | predator.maxspeed = 0.385; 63 | predator.maxforce = 0.020; 64 | predator.neighbordist = 16.0; 65 | predator.desiredseparation = 0.0; 66 | } 67 | } 68 | 69 | unsigned int drawFrame() { 70 | effects.DimAll(230); effects.ShowFrame(); 71 | 72 | bool applyWind = random(0, 255) > 250; 73 | if (applyWind) { 74 | wind.x = Boid::randomf() * .015; 75 | wind.y = Boid::randomf() * .015; 76 | } 77 | 78 | CRGB color = effects.ColorFromCurrentPalette(hue); 79 | 80 | for (int i = 0; i < boidCount; i++) { 81 | Boid * boid = &boids[i]; 82 | 83 | if (predatorPresent) { 84 | // flee from predator 85 | boid->repelForce(predator.location, 10); 86 | } 87 | 88 | boid->run(boids, boidCount); 89 | boid->wrapAroundBorders(); 90 | PVector location = boid->location; 91 | // PVector velocity = boid->velocity; 92 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 93 | // effects.leds[XY(location.x, location.y)] += color; 94 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 95 | 96 | if (applyWind) { 97 | boid->applyForce(wind); 98 | applyWind = false; 99 | } 100 | } 101 | 102 | if (predatorPresent) { 103 | predator.run(boids, boidCount); 104 | predator.wrapAroundBorders(); 105 | color = effects.ColorFromCurrentPalette(hue + 128); 106 | PVector location = predator.location; 107 | // PVector velocity = predator.velocity; 108 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 109 | // effects.leds[XY(location.x, location.y)] += color; 110 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 111 | } 112 | 113 | EVERY_N_MILLIS(200) { 114 | hue++; 115 | } 116 | 117 | EVERY_N_SECONDS(30) { 118 | predatorPresent = !predatorPresent; 119 | } 120 | 121 | return 0; 122 | } 123 | }; 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/PatternFlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | // Flocking 28 | // Daniel Shiffman 29 | // The Nature of Code, Spring 2009 30 | 31 | // Demonstration of Craig Reynolds' "Flocking" behavior 32 | // See: http://www.red3d.com/cwr/ 33 | // Rules: Cohesion, Separation, Alignment 34 | 35 | #ifndef PatternFlock_H 36 | #define PatternFlock_H 37 | 38 | class PatternFlock : public Drawable { 39 | public: 40 | PatternFlock() { 41 | name = (char *)"Flock"; 42 | } 43 | 44 | static const int boidCount = 10; 45 | Boid predator; 46 | 47 | PVector wind; 48 | byte hue = 0; 49 | bool predatorPresent = true; 50 | 51 | void start() { 52 | for (int i = 0; i < boidCount; i++) { 53 | boids[i] = Boid(15, 15); 54 | boids[i].maxspeed = 0.380; 55 | boids[i].maxforce = 0.015; 56 | } 57 | 58 | predatorPresent = random(0, 2) >= 1; 59 | if (predatorPresent) { 60 | predator = Boid(31, 31); 61 | predatorPresent = true; 62 | predator.maxspeed = 0.385; 63 | predator.maxforce = 0.020; 64 | predator.neighbordist = 16.0; 65 | predator.desiredseparation = 0.0; 66 | } 67 | } 68 | 69 | unsigned int drawFrame() { 70 | effects.DimAll(230); effects.ShowFrame(); 71 | 72 | bool applyWind = random(0, 255) > 250; 73 | if (applyWind) { 74 | wind.x = Boid::randomf() * .015; 75 | wind.y = Boid::randomf() * .015; 76 | } 77 | 78 | CRGB color = effects.ColorFromCurrentPalette(hue); 79 | 80 | for (int i = 0; i < boidCount; i++) { 81 | Boid * boid = &boids[i]; 82 | 83 | if (predatorPresent) { 84 | // flee from predator 85 | boid->repelForce(predator.location, 10); 86 | } 87 | 88 | boid->run(boids, boidCount); 89 | boid->wrapAroundBorders(); 90 | PVector location = boid->location; 91 | // PVector velocity = boid->velocity; 92 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 93 | // effects.leds[XY(location.x, location.y)] += color; 94 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 95 | 96 | if (applyWind) { 97 | boid->applyForce(wind); 98 | applyWind = false; 99 | } 100 | } 101 | 102 | if (predatorPresent) { 103 | predator.run(boids, boidCount); 104 | predator.wrapAroundBorders(); 105 | color = effects.ColorFromCurrentPalette(hue + 128); 106 | PVector location = predator.location; 107 | // PVector velocity = predator.velocity; 108 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 109 | // effects.leds[XY(location.x, location.y)] += color; 110 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 111 | } 112 | 113 | EVERY_N_MILLIS(200) { 114 | hue++; 115 | } 116 | 117 | EVERY_N_SECONDS(30) { 118 | predatorPresent = !predatorPresent; 119 | } 120 | 121 | return 0; 122 | } 123 | }; 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/PatternFlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | // Flocking 28 | // Daniel Shiffman 29 | // The Nature of Code, Spring 2009 30 | 31 | // Demonstration of Craig Reynolds' "Flocking" behavior 32 | // See: http://www.red3d.com/cwr/ 33 | // Rules: Cohesion, Separation, Alignment 34 | 35 | #ifndef PatternFlock_H 36 | #define PatternFlock_H 37 | 38 | class PatternFlock : public Drawable { 39 | public: 40 | PatternFlock() { 41 | name = (char *)"Flock"; 42 | } 43 | 44 | static const int boidCount = 10; 45 | Boid predator; 46 | 47 | PVector wind; 48 | byte hue = 0; 49 | bool predatorPresent = true; 50 | 51 | void start() { 52 | for (int i = 0; i < boidCount; i++) { 53 | boids[i] = Boid(15, 15); 54 | boids[i].maxspeed = 0.380; 55 | boids[i].maxforce = 0.015; 56 | } 57 | 58 | predatorPresent = random(0, 2) >= 1; 59 | if (predatorPresent) { 60 | predator = Boid(31, 31); 61 | predatorPresent = true; 62 | predator.maxspeed = 0.385; 63 | predator.maxforce = 0.020; 64 | predator.neighbordist = 16.0; 65 | predator.desiredseparation = 0.0; 66 | } 67 | } 68 | 69 | unsigned int drawFrame() { 70 | effects.DimAll(230); effects.ShowFrame(); 71 | 72 | bool applyWind = random(0, 255) > 250; 73 | if (applyWind) { 74 | wind.x = Boid::randomf() * .015; 75 | wind.y = Boid::randomf() * .015; 76 | } 77 | 78 | CRGB color = effects.ColorFromCurrentPalette(hue); 79 | 80 | for (int i = 0; i < boidCount; i++) { 81 | Boid * boid = &boids[i]; 82 | 83 | if (predatorPresent) { 84 | // flee from predator 85 | boid->repelForce(predator.location, 10); 86 | } 87 | 88 | boid->run(boids, boidCount); 89 | boid->wrapAroundBorders(); 90 | PVector location = boid->location; 91 | // PVector velocity = boid->velocity; 92 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 93 | // effects.leds[XY(location.x, location.y)] += color; 94 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 95 | 96 | if (applyWind) { 97 | boid->applyForce(wind); 98 | applyWind = false; 99 | } 100 | } 101 | 102 | if (predatorPresent) { 103 | predator.run(boids, boidCount); 104 | predator.wrapAroundBorders(); 105 | color = effects.ColorFromCurrentPalette(hue + 128); 106 | PVector location = predator.location; 107 | // PVector velocity = predator.velocity; 108 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 109 | // effects.leds[XY(location.x, location.y)] += color; 110 | effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color); 111 | } 112 | 113 | EVERY_N_MILLIS(200) { 114 | hue++; 115 | } 116 | 117 | EVERY_N_SECONDS(30) { 118 | predatorPresent = !predatorPresent; 119 | } 120 | 121 | return 0; 122 | } 123 | }; 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/mqtt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | WiFiClient wifiClient; 18 | PubSubClient mqttClient(wifiClient); 19 | 20 | // If we don't want to use the hostname 21 | // Useful if we'll have several of these devices in one room 22 | #define MQTT_NAME "glowingsquare/tube" 23 | 24 | char deviceTopic[40]; 25 | char inTopic[40]; 26 | char willTopic[40]; 27 | char roomStateTopic[40]; 28 | 29 | long lastMQTTReconnectAttempt = -10000; 30 | 31 | void mqttCallback(char* topic, byte* payload, unsigned int length) { 32 | 33 | // Convert the input bytes into a usable JSON buffer 34 | StaticJsonDocument<256> json; 35 | deserializeJson(json, payload, length); 36 | 37 | Serial.print("Receive message:"); 38 | serializeJsonPretty(json, Serial); 39 | Serial.print("\n"); 40 | 41 | // Handle room-wide topic messages 42 | if (strcmp(topic, roomStateTopic) == 0) { 43 | 44 | if (strcmp(json["party"], "chill") == 0) { 45 | Serial.println("^^^ Mode change: Chill party"); 46 | party_mode = 1; 47 | } else if (strcmp(json["party"], "on") == 0) { 48 | Serial.println("^^^ Mode change: Normal party"); 49 | party_mode = 2; 50 | } else if (strcmp(json["party"], "off") == 0) { 51 | Serial.println("^^^ Mode change: No party"); 52 | party_mode = 0; 53 | } 54 | 55 | } 56 | 57 | if (strcmp(topic, inTopic) == 0) { 58 | 59 | if (json["brightness"] || json["brightness"] == 0) { 60 | 61 | targetDisplayBrightness = json["brightness"].as(); 62 | 63 | } 64 | 65 | } 66 | 67 | } 68 | 69 | boolean mqttConnect() { 70 | 71 | Serial.print("=== MQTT connecting to "); 72 | Serial.print(mqtt_server); 73 | Serial.print(":"); 74 | Serial.println(atoi(mqtt_port)); 75 | 76 | // Use hostname as our client ID 77 | // Use our will topic to broadcast a "disconnected" message when device goes down 78 | if (mqttClient.connect(hostname, mqtt_username, mqtt_password, willTopic, 0, 1, "disconnected")) { 79 | 80 | // Announce the connection, and make our subscriptions 81 | mqttClient.publish(willTopic, "connected"); 82 | mqttClient.subscribe(inTopic); 83 | 84 | // This one is so we can set room-wide settings (like party mode etc.) 85 | mqttClient.subscribe(roomStateTopic); 86 | 87 | } else { 88 | 89 | // Sadness and tears. Check your MQTT params in portal 90 | Serial.println("%%% Failed to connect to MQTT"); 91 | 92 | } 93 | 94 | // Return true or false 95 | return mqttClient.connected(); 96 | 97 | } 98 | 99 | 100 | // Runs repeatedly from loop() in the main sketch 101 | // Maintains the connection and checks for new messages 102 | void mqttLoop() { 103 | 104 | long now = millis(); 105 | 106 | // Maintain connection 107 | // This is also how we connect for the first time 108 | if(!mqttClient.connected()) { 109 | 110 | // Has it been 5 seconds since we last tried to connect 111 | if (now - lastMQTTReconnectAttempt > 5000) { 112 | 113 | lastMQTTReconnectAttempt = now; 114 | 115 | // If successful, reset the counters 116 | if (mqttConnect()) { 117 | lastMQTTReconnectAttempt = 0; 118 | } 119 | } 120 | 121 | } else { 122 | 123 | // We are connected 124 | // Check for incoming messages 125 | mqttClient.loop(); 126 | 127 | } 128 | 129 | } 130 | 131 | // This runs once from setup() in the main sketch 132 | // It just takes the config (which has been loaded by this point) 133 | void setupMQTT() { 134 | 135 | char deviceID[40]; 136 | 137 | #ifdef MQTT_NAME 138 | strcpy(deviceID, MQTT_NAME); 139 | #else 140 | strcpy(deviceID, hostname); 141 | #endif 142 | 143 | // Format the topics to include the hostname 144 | sprintf(willTopic,"%s/%s/mqtt", room, deviceID); 145 | sprintf(inTopic,"%s/%s/in", room, deviceID); 146 | sprintf(deviceTopic,"%s/%s/out", room, deviceID); 147 | sprintf(roomStateTopic,"%s/state", room); 148 | 149 | // We store the port as a char[6] so need to convert 150 | mqttClient.setServer(mqtt_server, atoi(mqtt_port)); 151 | mqttClient.setCallback(mqttCallback); 152 | 153 | // Loop once to receive any initial messages 154 | for (int i = 0; i < 10; i++) { 155 | mqttLoop(); 156 | delay(100); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/mqtt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Flight Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | WiFiClient wifiClient; 18 | PubSubClient mqttClient(wifiClient); 19 | 20 | // If we don't want to use the hostname 21 | // Useful if we'll have several of these devices in one room 22 | #define MQTT_NAME "glowingsquare/flight" 23 | 24 | char deviceTopic[40]; 25 | char inTopic[40]; 26 | char willTopic[40]; 27 | char roomStateTopic[40]; 28 | 29 | long lastMQTTReconnectAttempt = -10000; 30 | 31 | void mqttCallback(char* topic, byte* payload, unsigned int length) { 32 | 33 | // Convert the input bytes into a usable JSON buffer 34 | StaticJsonDocument<256> json; 35 | deserializeJson(json, payload, length); 36 | 37 | Serial.print("Receive message:"); 38 | serializeJsonPretty(json, Serial); 39 | Serial.print("\n"); 40 | 41 | // Handle room-wide topic messages 42 | if (strcmp(topic, roomStateTopic) == 0) { 43 | 44 | if (strcmp(json["party"], "chill") == 0) { 45 | Serial.println("^^^ Mode change: Chill party"); 46 | party_mode = 1; 47 | } else if (strcmp(json["party"], "on") == 0) { 48 | Serial.println("^^^ Mode change: Normal party"); 49 | party_mode = 2; 50 | } else if (strcmp(json["party"], "off") == 0) { 51 | Serial.println("^^^ Mode change: No party"); 52 | party_mode = 0; 53 | } 54 | 55 | } 56 | 57 | if (strcmp(topic, inTopic) == 0) { 58 | 59 | if (json["brightness"] || json["brightness"] == 0) { 60 | 61 | targetDisplayBrightness = json["brightness"].as(); 62 | 63 | } 64 | 65 | } 66 | 67 | } 68 | 69 | boolean mqttConnect() { 70 | 71 | Serial.print("=== MQTT connecting to "); 72 | Serial.print(mqtt_server); 73 | Serial.print(":"); 74 | Serial.println(atoi(mqtt_port)); 75 | 76 | // Use hostname as our client ID 77 | // Use our will topic to broadcast a "disconnected" message when device goes down 78 | if (mqttClient.connect(hostname, mqtt_username, mqtt_password, willTopic, 0, 1, "disconnected")) { 79 | 80 | // Announce the connection, and make our subscriptions 81 | mqttClient.publish(willTopic, "connected"); 82 | mqttClient.subscribe(inTopic); 83 | 84 | // This one is so we can set room-wide settings (like party mode etc.) 85 | mqttClient.subscribe(roomStateTopic); 86 | 87 | } else { 88 | 89 | // Sadness and tears. Check your MQTT params in portal 90 | Serial.println("%%% Failed to connect to MQTT"); 91 | 92 | } 93 | 94 | // Return true or false 95 | return mqttClient.connected(); 96 | 97 | } 98 | 99 | 100 | // Runs repeatedly from loop() in the main sketch 101 | // Maintains the connection and checks for new messages 102 | void mqttLoop() { 103 | 104 | long now = millis(); 105 | 106 | // Maintain connection 107 | // This is also how we connect for the first time 108 | if(!mqttClient.connected()) { 109 | 110 | // Has it been 5 seconds since we last tried to connect 111 | if (now - lastMQTTReconnectAttempt > 5000) { 112 | 113 | lastMQTTReconnectAttempt = now; 114 | 115 | // If successful, reset the counters 116 | if (mqttConnect()) { 117 | lastMQTTReconnectAttempt = 0; 118 | } 119 | } 120 | 121 | } else { 122 | 123 | // We are connected 124 | // Check for incoming messages 125 | mqttClient.loop(); 126 | 127 | } 128 | 129 | } 130 | 131 | // This runs once from setup() in the main sketch 132 | // It just takes the config (which has been loaded by this point) 133 | void setupMQTT() { 134 | 135 | char deviceID[40]; 136 | 137 | #ifdef MQTT_NAME 138 | strcpy(deviceID, MQTT_NAME); 139 | #else 140 | strcpy(deviceID, hostname); 141 | #endif 142 | 143 | // Format the topics to include the hostname 144 | sprintf(willTopic,"%s/%s/mqtt", room, deviceID); 145 | sprintf(inTopic,"%s/%s/in", room, deviceID); 146 | sprintf(deviceTopic,"%s/%s/out", room, deviceID); 147 | sprintf(roomStateTopic,"%s/state", room); 148 | 149 | // We store the port as a char[6] so need to convert 150 | mqttClient.setServer(mqtt_server, atoi(mqtt_port)); 151 | mqttClient.setCallback(mqttCallback); 152 | 153 | // Loop once to receive any initial messages 154 | for (int i = 0; i < 10; i++) { 155 | mqttLoop(); 156 | delay(100); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/mqtt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Unifi Display |___/ 12 | For ESP32 13 | settings.h 14 | * 15 | */ 16 | 17 | WiFiClient wifiClient; 18 | PubSubClient mqttClient(wifiClient); 19 | 20 | // If we don't want to use the hostname 21 | // Useful if we'll have several of these devices in one room 22 | #define MQTT_NAME "glowingsquare/unifi" 23 | 24 | char deviceTopic[40]; 25 | char inTopic[40]; 26 | char willTopic[40]; 27 | char roomStateTopic[40]; 28 | 29 | long lastMQTTReconnectAttempt = -10000; 30 | 31 | void mqttCallback(char* topic, byte* payload, unsigned int length) { 32 | 33 | // Convert the input bytes into a usable JSON buffer 34 | StaticJsonDocument<256> json; 35 | deserializeJson(json, payload, length); 36 | 37 | Serial.print("Receive message:"); 38 | serializeJsonPretty(json, Serial); 39 | Serial.print("\n"); 40 | 41 | // Handle room-wide topic messages 42 | if (strcmp(topic, roomStateTopic) == 0) { 43 | 44 | if (strcmp(json["party"], "chill") == 0) { 45 | Serial.println("^^^ Mode change: Chill party"); 46 | party_mode = 1; 47 | } else if (strcmp(json["party"], "on") == 0) { 48 | Serial.println("^^^ Mode change: Normal party"); 49 | party_mode = 2; 50 | } else if (strcmp(json["party"], "off") == 0) { 51 | Serial.println("^^^ Mode change: No party"); 52 | party_mode = 0; 53 | } 54 | 55 | } 56 | 57 | if (strcmp(topic, inTopic) == 0) { 58 | 59 | if (json["brightness"] || json["brightness"] == 0) { 60 | 61 | targetDisplayBrightness = json["brightness"].as(); 62 | 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | } 70 | 71 | boolean mqttConnect() { 72 | 73 | Serial.print("=== MQTT connecting to "); 74 | Serial.print(mqtt_server); 75 | Serial.print(":"); 76 | Serial.println(atoi(mqtt_port)); 77 | 78 | // Use hostname as our client ID 79 | // Use our will topic to broadcast a "disconnected" message when device goes down 80 | if (mqttClient.connect(hostname, mqtt_username, mqtt_password, willTopic, 0, 1, "disconnected")) { 81 | 82 | // Announce the connection, and make our subscriptions 83 | mqttClient.publish(willTopic, "connected"); 84 | mqttClient.subscribe(inTopic); 85 | 86 | // This one is so we can set room-wide settings (like party mode etc.) 87 | mqttClient.subscribe(roomStateTopic); 88 | 89 | } else { 90 | 91 | // Sadness and tears. Check your MQTT params in portal 92 | Serial.println("%%% Failed to connect to MQTT"); 93 | 94 | } 95 | 96 | // Return true or false 97 | return mqttClient.connected(); 98 | 99 | } 100 | 101 | 102 | // Runs repeatedly from loop() in the main sketch 103 | // Maintains the connection and checks for new messages 104 | void mqttLoop() { 105 | 106 | long now = millis(); 107 | 108 | // Maintain connection 109 | // This is also how we connect for the first time 110 | if(!mqttClient.connected()) { 111 | 112 | // Has it been 5 seconds since we last tried to connect 113 | if (now - lastMQTTReconnectAttempt > 5000) { 114 | 115 | lastMQTTReconnectAttempt = now; 116 | 117 | // If successful, reset the counters 118 | if (mqttConnect()) { 119 | lastMQTTReconnectAttempt = 0; 120 | } 121 | } 122 | 123 | } else { 124 | 125 | // We are connected 126 | // Check for incoming messages 127 | mqttClient.loop(); 128 | 129 | } 130 | 131 | } 132 | 133 | // This runs once from setup() in the main sketch 134 | // It just takes the config (which has been loaded by this point) 135 | void setupMQTT() { 136 | 137 | char deviceID[40]; 138 | 139 | #ifdef MQTT_NAME 140 | strcpy(deviceID, MQTT_NAME); 141 | #else 142 | strcpy(deviceID, hostname); 143 | #endif 144 | 145 | // Format the topics to include the hostname 146 | sprintf(willTopic,"%s/%s/mqtt", room, deviceID); 147 | sprintf(inTopic,"%s/%s/in", room, deviceID); 148 | sprintf(deviceTopic,"%s/%s/out", room, deviceID); 149 | sprintf(roomStateTopic,"%s/state", room); 150 | 151 | // We store the port as a char[6] so need to convert 152 | mqttClient.setServer(mqtt_server, atoi(mqtt_port)); 153 | mqttClient.setCallback(mqttCallback); 154 | 155 | // Loop once to receive any initial messages 156 | for (int i = 0; i < 10; i++) { 157 | mqttLoop(); 158 | delay(100); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/Vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Vector_H 24 | #define Vector_H 25 | 26 | template 27 | class Vector2 { 28 | public: 29 | T x, y; 30 | 31 | Vector2() :x(0), y(0) {} 32 | Vector2(T x, T y) : x(x), y(y) {} 33 | Vector2(const Vector2& v) : x(v.x), y(v.y) {} 34 | 35 | Vector2& operator=(const Vector2& v) { 36 | x = v.x; 37 | y = v.y; 38 | return *this; 39 | } 40 | 41 | bool isEmpty() { 42 | return x == 0 && y == 0; 43 | } 44 | 45 | bool operator==(Vector2& v) { 46 | return x == v.x && y == v.y; 47 | } 48 | 49 | bool operator!=(Vector2& v) { 50 | return !(x == y); 51 | } 52 | 53 | Vector2 operator+(Vector2& v) { 54 | return Vector2(x + v.x, y + v.y); 55 | } 56 | Vector2 operator-(Vector2& v) { 57 | return Vector2(x - v.x, y - v.y); 58 | } 59 | 60 | Vector2& operator+=(Vector2& v) { 61 | x += v.x; 62 | y += v.y; 63 | return *this; 64 | } 65 | Vector2& operator-=(Vector2& v) { 66 | x -= v.x; 67 | y -= v.y; 68 | return *this; 69 | } 70 | 71 | Vector2 operator+(double s) { 72 | return Vector2(x + s, y + s); 73 | } 74 | Vector2 operator-(double s) { 75 | return Vector2(x - s, y - s); 76 | } 77 | Vector2 operator*(double s) { 78 | return Vector2(x * s, y * s); 79 | } 80 | Vector2 operator/(double s) { 81 | return Vector2(x / s, y / s); 82 | } 83 | 84 | Vector2& operator+=(double s) { 85 | x += s; 86 | y += s; 87 | return *this; 88 | } 89 | Vector2& operator-=(double s) { 90 | x -= s; 91 | y -= s; 92 | return *this; 93 | } 94 | Vector2& operator*=(double s) { 95 | x *= s; 96 | y *= s; 97 | return *this; 98 | } 99 | Vector2& operator/=(double s) { 100 | x /= s; 101 | y /= s; 102 | return *this; 103 | } 104 | 105 | void set(T x, T y) { 106 | this->x = x; 107 | this->y = y; 108 | } 109 | 110 | void rotate(double deg) { 111 | double theta = deg / 180.0 * M_PI; 112 | double c = cos(theta); 113 | double s = sin(theta); 114 | double tx = x * c - y * s; 115 | double ty = x * s + y * c; 116 | x = tx; 117 | y = ty; 118 | } 119 | 120 | Vector2& normalize() { 121 | if (length() == 0) return *this; 122 | *this *= (1.0 / length()); 123 | return *this; 124 | } 125 | 126 | float dist(Vector2 v) const { 127 | Vector2 d(v.x - x, v.y - y); 128 | return d.length(); 129 | } 130 | float length() const { 131 | return sqrt(x * x + y * y); 132 | } 133 | 134 | float mag() const { 135 | return length(); 136 | } 137 | 138 | float magSq() { 139 | return (x * x + y * y); 140 | } 141 | 142 | void truncate(double length) { 143 | double angle = atan2f(y, x); 144 | x = length * cos(angle); 145 | y = length * sin(angle); 146 | } 147 | 148 | Vector2 ortho() const { 149 | return Vector2(y, -x); 150 | } 151 | 152 | static float dot(Vector2 v1, Vector2 v2) { 153 | return v1.x * v2.x + v1.y * v2.y; 154 | } 155 | static float cross(Vector2 v1, Vector2 v2) { 156 | return (v1.x * v2.y) - (v1.y * v2.x); 157 | } 158 | 159 | void limit(float max) { 160 | if (magSq() > max*max) { 161 | normalize(); 162 | *this *= max; 163 | } 164 | } 165 | }; 166 | 167 | typedef Vector2 PVector; 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/PatternSnake.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from LedEffects Snake by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Snake.cpp?at=default 6 | * Copyright (c) 2013 Robert Atkins 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSnake_H 27 | #define PatternSnake_H 28 | 29 | class PatternSnake : public Drawable { 30 | private: 31 | static const byte SNAKE_LENGTH = 16; 32 | 33 | CRGB colors[SNAKE_LENGTH]; 34 | uint8_t initialHue; 35 | 36 | enum Direction { 37 | UP, DOWN, LEFT, RIGHT 38 | }; 39 | 40 | struct Pixel { 41 | uint8_t x; 42 | uint8_t y; 43 | }; 44 | 45 | struct Snake { 46 | Pixel pixels[SNAKE_LENGTH]; 47 | 48 | Direction direction; 49 | 50 | void newDirection() { 51 | switch (direction) { 52 | case UP: 53 | case DOWN: 54 | direction = random(0, 2) == 1 ? RIGHT : LEFT; 55 | break; 56 | 57 | case LEFT: 58 | case RIGHT: 59 | direction = random(0, 2) == 1 ? DOWN : UP; 60 | 61 | default: 62 | break; 63 | } 64 | } 65 | 66 | void shuffleDown() { 67 | for (byte i = SNAKE_LENGTH - 1; i > 0; i--) { 68 | pixels[i] = pixels[i - 1]; 69 | } 70 | } 71 | 72 | void reset() { 73 | direction = UP; 74 | for (int i = 0; i < SNAKE_LENGTH; i++) { 75 | pixels[i].x = 0; 76 | pixels[i].y = 0; 77 | } 78 | } 79 | 80 | void move() { 81 | switch (direction) { 82 | case UP: 83 | pixels[0].y = (pixels[0].y + 1) % MATRIX_HEIGHT; 84 | break; 85 | case LEFT: 86 | pixels[0].x = (pixels[0].x + 1) % MATRIX_WIDTH; 87 | break; 88 | case DOWN: 89 | pixels[0].y = pixels[0].y == 0 ? MATRIX_HEIGHT - 1 : pixels[0].y - 1; 90 | break; 91 | case RIGHT: 92 | pixels[0].x = pixels[0].x == 0 ? MATRIX_WIDTH - 1 : pixels[0].x - 1; 93 | break; 94 | } 95 | } 96 | 97 | void draw(CRGB colors[SNAKE_LENGTH]) { 98 | for (byte i = 0; i < SNAKE_LENGTH; i++) { 99 | effects.leds[XY(pixels[i].x, pixels[i].y)] = colors[i] %= (255 - i * (255 / SNAKE_LENGTH)); 100 | } 101 | } 102 | }; 103 | 104 | static const int snakeCount = 6; 105 | Snake snakes[snakeCount]; 106 | 107 | public: 108 | PatternSnake() { 109 | name = (char *)"Snake"; 110 | for (int i = 0; i < snakeCount; i++) { 111 | Snake* snake = &snakes[i]; 112 | snake->reset(); 113 | } 114 | } 115 | 116 | void start() 117 | { 118 | effects.ClearFrame(); 119 | } 120 | 121 | unsigned int drawFrame() { 122 | 123 | 124 | fill_palette(colors, SNAKE_LENGTH, initialHue++, 5, effects.currentPalette, 255, LINEARBLEND); 125 | 126 | for (int i = 0; i < snakeCount; i++) { 127 | Snake* snake = &snakes[i]; 128 | 129 | snake->shuffleDown(); 130 | 131 | if (random(10) > 7) { 132 | snake->newDirection(); 133 | } 134 | 135 | snake->move(); 136 | snake->draw(colors); 137 | } 138 | 139 | effects.ShowFrame(); 140 | 141 | return 30; 142 | } 143 | }; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/Vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Vector_H 24 | #define Vector_H 25 | 26 | template 27 | class Vector2 { 28 | public: 29 | T x, y; 30 | 31 | Vector2() :x(0), y(0) {} 32 | Vector2(T x, T y) : x(x), y(y) {} 33 | Vector2(const Vector2& v) : x(v.x), y(v.y) {} 34 | 35 | Vector2& operator=(const Vector2& v) { 36 | x = v.x; 37 | y = v.y; 38 | return *this; 39 | } 40 | 41 | bool isEmpty() { 42 | return x == 0 && y == 0; 43 | } 44 | 45 | bool operator==(Vector2& v) { 46 | return x == v.x && y == v.y; 47 | } 48 | 49 | bool operator!=(Vector2& v) { 50 | return !(x == y); 51 | } 52 | 53 | Vector2 operator+(Vector2& v) { 54 | return Vector2(x + v.x, y + v.y); 55 | } 56 | Vector2 operator-(Vector2& v) { 57 | return Vector2(x - v.x, y - v.y); 58 | } 59 | 60 | Vector2& operator+=(Vector2& v) { 61 | x += v.x; 62 | y += v.y; 63 | return *this; 64 | } 65 | Vector2& operator-=(Vector2& v) { 66 | x -= v.x; 67 | y -= v.y; 68 | return *this; 69 | } 70 | 71 | Vector2 operator+(double s) { 72 | return Vector2(x + s, y + s); 73 | } 74 | Vector2 operator-(double s) { 75 | return Vector2(x - s, y - s); 76 | } 77 | Vector2 operator*(double s) { 78 | return Vector2(x * s, y * s); 79 | } 80 | Vector2 operator/(double s) { 81 | return Vector2(x / s, y / s); 82 | } 83 | 84 | Vector2& operator+=(double s) { 85 | x += s; 86 | y += s; 87 | return *this; 88 | } 89 | Vector2& operator-=(double s) { 90 | x -= s; 91 | y -= s; 92 | return *this; 93 | } 94 | Vector2& operator*=(double s) { 95 | x *= s; 96 | y *= s; 97 | return *this; 98 | } 99 | Vector2& operator/=(double s) { 100 | x /= s; 101 | y /= s; 102 | return *this; 103 | } 104 | 105 | void set(T x, T y) { 106 | this->x = x; 107 | this->y = y; 108 | } 109 | 110 | void rotate(double deg) { 111 | double theta = deg / 180.0 * M_PI; 112 | double c = cos(theta); 113 | double s = sin(theta); 114 | double tx = x * c - y * s; 115 | double ty = x * s + y * c; 116 | x = tx; 117 | y = ty; 118 | } 119 | 120 | Vector2& normalize() { 121 | if (length() == 0) return *this; 122 | *this *= (1.0 / length()); 123 | return *this; 124 | } 125 | 126 | float dist(Vector2 v) const { 127 | Vector2 d(v.x - x, v.y - y); 128 | return d.length(); 129 | } 130 | float length() const { 131 | return sqrt(x * x + y * y); 132 | } 133 | 134 | float mag() const { 135 | return length(); 136 | } 137 | 138 | float magSq() { 139 | return (x * x + y * y); 140 | } 141 | 142 | void truncate(double length) { 143 | double angle = atan2f(y, x); 144 | x = length * cos(angle); 145 | y = length * sin(angle); 146 | } 147 | 148 | Vector2 ortho() const { 149 | return Vector2(y, -x); 150 | } 151 | 152 | static float dot(Vector2 v1, Vector2 v2) { 153 | return v1.x * v2.x + v1.y * v2.y; 154 | } 155 | static float cross(Vector2 v1, Vector2 v2) { 156 | return (v1.x * v2.y) - (v1.y * v2.x); 157 | } 158 | 159 | void limit(float max) { 160 | if (magSq() > max*max) { 161 | normalize(); 162 | *this *= max; 163 | } 164 | } 165 | }; 166 | 167 | typedef Vector2 PVector; 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/PatternSnake.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from LedEffects Snake by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Snake.cpp?at=default 6 | * Copyright (c) 2013 Robert Atkins 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSnake_H 27 | #define PatternSnake_H 28 | 29 | class PatternSnake : public Drawable { 30 | private: 31 | static const byte SNAKE_LENGTH = 16; 32 | 33 | CRGB colors[SNAKE_LENGTH]; 34 | uint8_t initialHue; 35 | 36 | enum Direction { 37 | UP, DOWN, LEFT, RIGHT 38 | }; 39 | 40 | struct Pixel { 41 | uint8_t x; 42 | uint8_t y; 43 | }; 44 | 45 | struct Snake { 46 | Pixel pixels[SNAKE_LENGTH]; 47 | 48 | Direction direction; 49 | 50 | void newDirection() { 51 | switch (direction) { 52 | case UP: 53 | case DOWN: 54 | direction = random(0, 2) == 1 ? RIGHT : LEFT; 55 | break; 56 | 57 | case LEFT: 58 | case RIGHT: 59 | direction = random(0, 2) == 1 ? DOWN : UP; 60 | 61 | default: 62 | break; 63 | } 64 | } 65 | 66 | void shuffleDown() { 67 | for (byte i = SNAKE_LENGTH - 1; i > 0; i--) { 68 | pixels[i] = pixels[i - 1]; 69 | } 70 | } 71 | 72 | void reset() { 73 | direction = UP; 74 | for (int i = 0; i < SNAKE_LENGTH; i++) { 75 | pixels[i].x = 0; 76 | pixels[i].y = 0; 77 | } 78 | } 79 | 80 | void move() { 81 | switch (direction) { 82 | case UP: 83 | pixels[0].y = (pixels[0].y + 1) % MATRIX_HEIGHT; 84 | break; 85 | case LEFT: 86 | pixels[0].x = (pixels[0].x + 1) % MATRIX_WIDTH; 87 | break; 88 | case DOWN: 89 | pixels[0].y = pixels[0].y == 0 ? MATRIX_HEIGHT - 1 : pixels[0].y - 1; 90 | break; 91 | case RIGHT: 92 | pixels[0].x = pixels[0].x == 0 ? MATRIX_WIDTH - 1 : pixels[0].x - 1; 93 | break; 94 | } 95 | } 96 | 97 | void draw(CRGB colors[SNAKE_LENGTH]) { 98 | for (byte i = 0; i < SNAKE_LENGTH; i++) { 99 | effects.leds[XY(pixels[i].x, pixels[i].y)] = colors[i] %= (255 - i * (255 / SNAKE_LENGTH)); 100 | } 101 | } 102 | }; 103 | 104 | static const int snakeCount = 6; 105 | Snake snakes[snakeCount]; 106 | 107 | public: 108 | PatternSnake() { 109 | name = (char *)"Snake"; 110 | for (int i = 0; i < snakeCount; i++) { 111 | Snake* snake = &snakes[i]; 112 | snake->reset(); 113 | } 114 | } 115 | 116 | void start() 117 | { 118 | effects.ClearFrame(); 119 | } 120 | 121 | unsigned int drawFrame() { 122 | 123 | 124 | fill_palette(colors, SNAKE_LENGTH, initialHue++, 5, effects.currentPalette, 255, LINEARBLEND); 125 | 126 | for (int i = 0; i < snakeCount; i++) { 127 | Snake* snake = &snakes[i]; 128 | 129 | snake->shuffleDown(); 130 | 131 | if (random(10) > 7) { 132 | snake->newDirection(); 133 | } 134 | 135 | snake->move(); 136 | snake->draw(colors); 137 | } 138 | 139 | effects.ShowFrame(); 140 | 141 | return 30; 142 | } 143 | }; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/PatternSnake.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from LedEffects Snake by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Snake.cpp?at=default 6 | * Copyright (c) 2013 Robert Atkins 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSnake_H 27 | #define PatternSnake_H 28 | 29 | class PatternSnake : public Drawable { 30 | private: 31 | static const byte SNAKE_LENGTH = 16; 32 | 33 | CRGB colors[SNAKE_LENGTH]; 34 | uint8_t initialHue; 35 | 36 | enum Direction { 37 | UP, DOWN, LEFT, RIGHT 38 | }; 39 | 40 | struct Pixel { 41 | uint8_t x; 42 | uint8_t y; 43 | }; 44 | 45 | struct Snake { 46 | Pixel pixels[SNAKE_LENGTH]; 47 | 48 | Direction direction; 49 | 50 | void newDirection() { 51 | switch (direction) { 52 | case UP: 53 | case DOWN: 54 | direction = random(0, 2) == 1 ? RIGHT : LEFT; 55 | break; 56 | 57 | case LEFT: 58 | case RIGHT: 59 | direction = random(0, 2) == 1 ? DOWN : UP; 60 | 61 | default: 62 | break; 63 | } 64 | } 65 | 66 | void shuffleDown() { 67 | for (byte i = SNAKE_LENGTH - 1; i > 0; i--) { 68 | pixels[i] = pixels[i - 1]; 69 | } 70 | } 71 | 72 | void reset() { 73 | direction = UP; 74 | for (int i = 0; i < SNAKE_LENGTH; i++) { 75 | pixels[i].x = 0; 76 | pixels[i].y = 0; 77 | } 78 | } 79 | 80 | void move() { 81 | switch (direction) { 82 | case UP: 83 | pixels[0].y = (pixels[0].y + 1) % MATRIX_HEIGHT; 84 | break; 85 | case LEFT: 86 | pixels[0].x = (pixels[0].x + 1) % MATRIX_WIDTH; 87 | break; 88 | case DOWN: 89 | pixels[0].y = pixels[0].y == 0 ? MATRIX_HEIGHT - 1 : pixels[0].y - 1; 90 | break; 91 | case RIGHT: 92 | pixels[0].x = pixels[0].x == 0 ? MATRIX_WIDTH - 1 : pixels[0].x - 1; 93 | break; 94 | } 95 | } 96 | 97 | void draw(CRGB colors[SNAKE_LENGTH]) { 98 | for (byte i = 0; i < SNAKE_LENGTH; i++) { 99 | effects.leds[XY(pixels[i].x, pixels[i].y)] = colors[i] %= (255 - i * (255 / SNAKE_LENGTH)); 100 | } 101 | } 102 | }; 103 | 104 | static const int snakeCount = 6; 105 | Snake snakes[snakeCount]; 106 | 107 | public: 108 | PatternSnake() { 109 | name = (char *)"Snake"; 110 | for (int i = 0; i < snakeCount; i++) { 111 | Snake* snake = &snakes[i]; 112 | snake->reset(); 113 | } 114 | } 115 | 116 | void start() 117 | { 118 | effects.ClearFrame(); 119 | } 120 | 121 | unsigned int drawFrame() { 122 | 123 | 124 | fill_palette(colors, SNAKE_LENGTH, initialHue++, 5, effects.currentPalette, 255, LINEARBLEND); 125 | 126 | for (int i = 0; i < snakeCount; i++) { 127 | Snake* snake = &snakes[i]; 128 | 129 | snake->shuffleDown(); 130 | 131 | if (random(10) > 7) { 132 | snake->newDirection(); 133 | } 134 | 135 | snake->move(); 136 | snake->draw(colors); 137 | } 138 | 139 | effects.ShowFrame(); 140 | 141 | return 30; 142 | } 143 | }; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/Vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Vector_H 24 | #define Vector_H 25 | 26 | template 27 | class Vector2 { 28 | public: 29 | T x, y; 30 | 31 | Vector2() :x(0), y(0) {} 32 | Vector2(T x, T y) : x(x), y(y) {} 33 | Vector2(const Vector2& v) : x(v.x), y(v.y) {} 34 | 35 | Vector2& operator=(const Vector2& v) { 36 | x = v.x; 37 | y = v.y; 38 | return *this; 39 | } 40 | 41 | bool isEmpty() { 42 | return x == 0 && y == 0; 43 | } 44 | 45 | bool operator==(Vector2& v) { 46 | return x == v.x && y == v.y; 47 | } 48 | 49 | bool operator!=(Vector2& v) { 50 | return !(x == y); 51 | } 52 | 53 | Vector2 operator+(Vector2& v) { 54 | return Vector2(x + v.x, y + v.y); 55 | } 56 | Vector2 operator-(Vector2& v) { 57 | return Vector2(x - v.x, y - v.y); 58 | } 59 | 60 | Vector2& operator+=(Vector2& v) { 61 | x += v.x; 62 | y += v.y; 63 | return *this; 64 | } 65 | Vector2& operator-=(Vector2& v) { 66 | x -= v.x; 67 | y -= v.y; 68 | return *this; 69 | } 70 | 71 | Vector2 operator+(double s) { 72 | return Vector2(x + s, y + s); 73 | } 74 | Vector2 operator-(double s) { 75 | return Vector2(x - s, y - s); 76 | } 77 | Vector2 operator*(double s) { 78 | return Vector2(x * s, y * s); 79 | } 80 | Vector2 operator/(double s) { 81 | return Vector2(x / s, y / s); 82 | } 83 | 84 | Vector2& operator+=(double s) { 85 | x += s; 86 | y += s; 87 | return *this; 88 | } 89 | Vector2& operator-=(double s) { 90 | x -= s; 91 | y -= s; 92 | return *this; 93 | } 94 | Vector2& operator*=(double s) { 95 | x *= s; 96 | y *= s; 97 | return *this; 98 | } 99 | Vector2& operator/=(double s) { 100 | x /= s; 101 | y /= s; 102 | return *this; 103 | } 104 | 105 | void set(T x, T y) { 106 | this->x = x; 107 | this->y = y; 108 | } 109 | 110 | void rotate(double deg) { 111 | double theta = deg / 180.0 * M_PI; 112 | double c = cos(theta); 113 | double s = sin(theta); 114 | double tx = x * c - y * s; 115 | double ty = x * s + y * c; 116 | x = tx; 117 | y = ty; 118 | } 119 | 120 | Vector2& normalize() { 121 | if (length() == 0) return *this; 122 | *this *= (1.0 / length()); 123 | return *this; 124 | } 125 | 126 | float dist(Vector2 v) const { 127 | Vector2 d(v.x - x, v.y - y); 128 | return d.length(); 129 | } 130 | float length() const { 131 | return sqrt(x * x + y * y); 132 | } 133 | 134 | float mag() const { 135 | return length(); 136 | } 137 | 138 | float magSq() { 139 | return (x * x + y * y); 140 | } 141 | 142 | void truncate(double length) { 143 | double angle = atan2f(y, x); 144 | x = length * cos(angle); 145 | y = length * sin(angle); 146 | } 147 | 148 | Vector2 ortho() const { 149 | return Vector2(y, -x); 150 | } 151 | 152 | static float dot(Vector2 v1, Vector2 v2) { 153 | return v1.x * v2.x + v1.y * v2.y; 154 | } 155 | static float cross(Vector2 v1, Vector2 v2) { 156 | return (v1.x * v2.y) - (v1.y * v2.x); 157 | } 158 | 159 | void limit(float max) { 160 | if (magSq() > max*max) { 161 | normalize(); 162 | *this *= max; 163 | } 164 | } 165 | }; 166 | 167 | typedef Vector2 PVector; 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/PatternSpiral.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: 3 | * https://gist.github.com/anonymous/876f908333cd95315c35 4 | * 5 | * Copyright (c) 2014 Stefan Petrick 6 | * http://www.stefan-petrick.de/wordpress_beta 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSpiral_H 27 | #define PatternSpiral_H 28 | 29 | class PatternSpiral : public Drawable { 30 | private: 31 | // Timer stuff (Oszillators) 32 | struct timer { 33 | unsigned long takt; 34 | unsigned long lastMillis; 35 | unsigned long count; 36 | int delta; 37 | byte up; 38 | byte down; 39 | }; 40 | timer multiTimer[5]; 41 | 42 | int timers = sizeof(multiTimer) / sizeof(multiTimer[0]); 43 | 44 | // counts all variables with different speeds linear up and down 45 | void UpdateTimers() 46 | { 47 | unsigned long now = millis(); 48 | for (int i = 0; i < timers; i++) 49 | { 50 | while (now - multiTimer[i].lastMillis >= multiTimer[i].takt) 51 | { 52 | multiTimer[i].lastMillis += multiTimer[i].takt; 53 | multiTimer[i].count = multiTimer[i].count + multiTimer[i].delta; 54 | if ((multiTimer[i].count == multiTimer[i].up) || (multiTimer[i].count == multiTimer[i].down)) 55 | { 56 | multiTimer[i].delta = -multiTimer[i].delta; 57 | } 58 | } 59 | } 60 | } 61 | 62 | public: 63 | PatternSpiral() { 64 | name = (char *)"Spiral"; 65 | } 66 | 67 | void start() { 68 | // set all counting directions positive for the beginning 69 | for (int i = 0; i < timers; i++) multiTimer[i].delta = 1; 70 | 71 | // set range (up/down), speed (takt=ms between steps) and starting point of all oszillators 72 | 73 | unsigned long now = millis(); 74 | 75 | multiTimer[0].lastMillis = now; 76 | multiTimer[0].takt = 42; //x1 77 | multiTimer[0].up = MATRIX_WIDTH - 1; 78 | multiTimer[0].down = 0; 79 | multiTimer[0].count = 0; 80 | 81 | multiTimer[1].lastMillis = now; 82 | multiTimer[1].takt = 55; //y1 83 | multiTimer[1].up = MATRIX_HEIGHT - 1; 84 | multiTimer[1].down = 0; 85 | multiTimer[1].count = 0; 86 | 87 | multiTimer[2].lastMillis = now; 88 | multiTimer[2].takt = 3; //color 89 | multiTimer[2].up = 255; 90 | multiTimer[2].down = 0; 91 | multiTimer[2].count = 0; 92 | 93 | multiTimer[3].lastMillis = now; 94 | multiTimer[3].takt = 71; //x2 95 | multiTimer[3].up = MATRIX_WIDTH - 1; 96 | multiTimer[3].down = 0; 97 | multiTimer[3].count = 0; 98 | 99 | multiTimer[4].lastMillis = now; 100 | multiTimer[4].takt = 89; //y2 101 | multiTimer[4].up = MATRIX_HEIGHT - 1; 102 | multiTimer[4].down = 0; 103 | multiTimer[4].count = 0; 104 | } 105 | 106 | unsigned int drawFrame() { 107 | // manage the Oszillators 108 | UpdateTimers(); 109 | 110 | // draw just a line defined by 5 oszillators 111 | effects.BresenhamLine( 112 | multiTimer[3].count, // x1 113 | multiTimer[4].count, // y1 114 | multiTimer[0].count, // x2 115 | multiTimer[1].count, // y2 116 | multiTimer[2].count); // color 117 | 118 | // manipulate the screen buffer 119 | // with fixed parameters (could be oszillators too) 120 | // Params: center x, y, radius, scale color down 121 | // --> NOTE: Affects always a SQUARE with an odd length 122 | // effects.SpiralStream(15, 15, 10, 128); 123 | 124 | effects.SpiralStream(31, 15, 64, 128); // for 64 pixel wide matrix! 125 | // effects.SpiralStream(47, 15, 10, 128); // for 64 pixel wide matrix! 126 | 127 | // why not several times?! 128 | // effects.SpiralStream(16, 6, 6, 128); 129 | // effects.SpiralStream(10, 24, 10, 128); 130 | 131 | // increase the contrast 132 | effects.DimAll(250); effects.ShowFrame(); 133 | 134 | return 0; 135 | } 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/PatternSpiral.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: 3 | * https://gist.github.com/anonymous/876f908333cd95315c35 4 | * 5 | * Copyright (c) 2014 Stefan Petrick 6 | * http://www.stefan-petrick.de/wordpress_beta 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSpiral_H 27 | #define PatternSpiral_H 28 | 29 | class PatternSpiral : public Drawable { 30 | private: 31 | // Timer stuff (Oszillators) 32 | struct timer { 33 | unsigned long takt; 34 | unsigned long lastMillis; 35 | unsigned long count; 36 | int delta; 37 | byte up; 38 | byte down; 39 | }; 40 | timer multiTimer[5]; 41 | 42 | int timers = sizeof(multiTimer) / sizeof(multiTimer[0]); 43 | 44 | // counts all variables with different speeds linear up and down 45 | void UpdateTimers() 46 | { 47 | unsigned long now = millis(); 48 | for (int i = 0; i < timers; i++) 49 | { 50 | while (now - multiTimer[i].lastMillis >= multiTimer[i].takt) 51 | { 52 | multiTimer[i].lastMillis += multiTimer[i].takt; 53 | multiTimer[i].count = multiTimer[i].count + multiTimer[i].delta; 54 | if ((multiTimer[i].count == multiTimer[i].up) || (multiTimer[i].count == multiTimer[i].down)) 55 | { 56 | multiTimer[i].delta = -multiTimer[i].delta; 57 | } 58 | } 59 | } 60 | } 61 | 62 | public: 63 | PatternSpiral() { 64 | name = (char *)"Spiral"; 65 | } 66 | 67 | void start() { 68 | // set all counting directions positive for the beginning 69 | for (int i = 0; i < timers; i++) multiTimer[i].delta = 1; 70 | 71 | // set range (up/down), speed (takt=ms between steps) and starting point of all oszillators 72 | 73 | unsigned long now = millis(); 74 | 75 | multiTimer[0].lastMillis = now; 76 | multiTimer[0].takt = 42; //x1 77 | multiTimer[0].up = MATRIX_WIDTH - 1; 78 | multiTimer[0].down = 0; 79 | multiTimer[0].count = 0; 80 | 81 | multiTimer[1].lastMillis = now; 82 | multiTimer[1].takt = 55; //y1 83 | multiTimer[1].up = MATRIX_HEIGHT - 1; 84 | multiTimer[1].down = 0; 85 | multiTimer[1].count = 0; 86 | 87 | multiTimer[2].lastMillis = now; 88 | multiTimer[2].takt = 3; //color 89 | multiTimer[2].up = 255; 90 | multiTimer[2].down = 0; 91 | multiTimer[2].count = 0; 92 | 93 | multiTimer[3].lastMillis = now; 94 | multiTimer[3].takt = 71; //x2 95 | multiTimer[3].up = MATRIX_WIDTH - 1; 96 | multiTimer[3].down = 0; 97 | multiTimer[3].count = 0; 98 | 99 | multiTimer[4].lastMillis = now; 100 | multiTimer[4].takt = 89; //y2 101 | multiTimer[4].up = MATRIX_HEIGHT - 1; 102 | multiTimer[4].down = 0; 103 | multiTimer[4].count = 0; 104 | } 105 | 106 | unsigned int drawFrame() { 107 | // manage the Oszillators 108 | UpdateTimers(); 109 | 110 | // draw just a line defined by 5 oszillators 111 | effects.BresenhamLine( 112 | multiTimer[3].count, // x1 113 | multiTimer[4].count, // y1 114 | multiTimer[0].count, // x2 115 | multiTimer[1].count, // y2 116 | multiTimer[2].count); // color 117 | 118 | // manipulate the screen buffer 119 | // with fixed parameters (could be oszillators too) 120 | // Params: center x, y, radius, scale color down 121 | // --> NOTE: Affects always a SQUARE with an odd length 122 | // effects.SpiralStream(15, 15, 10, 128); 123 | 124 | effects.SpiralStream(31, 15, 64, 128); // for 64 pixel wide matrix! 125 | // effects.SpiralStream(47, 15, 10, 128); // for 64 pixel wide matrix! 126 | 127 | // why not several times?! 128 | // effects.SpiralStream(16, 6, 6, 128); 129 | // effects.SpiralStream(10, 24, 10, 128); 130 | 131 | // increase the contrast 132 | effects.DimAll(250); effects.ShowFrame(); 133 | 134 | return 0; 135 | } 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/PatternSpiral.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: 3 | * https://gist.github.com/anonymous/876f908333cd95315c35 4 | * 5 | * Copyright (c) 2014 Stefan Petrick 6 | * http://www.stefan-petrick.de/wordpress_beta 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSpiral_H 27 | #define PatternSpiral_H 28 | 29 | class PatternSpiral : public Drawable { 30 | private: 31 | // Timer stuff (Oszillators) 32 | struct timer { 33 | unsigned long takt; 34 | unsigned long lastMillis; 35 | unsigned long count; 36 | int delta; 37 | byte up; 38 | byte down; 39 | }; 40 | timer multiTimer[5]; 41 | 42 | int timers = sizeof(multiTimer) / sizeof(multiTimer[0]); 43 | 44 | // counts all variables with different speeds linear up and down 45 | void UpdateTimers() 46 | { 47 | unsigned long now = millis(); 48 | for (int i = 0; i < timers; i++) 49 | { 50 | while (now - multiTimer[i].lastMillis >= multiTimer[i].takt) 51 | { 52 | multiTimer[i].lastMillis += multiTimer[i].takt; 53 | multiTimer[i].count = multiTimer[i].count + multiTimer[i].delta; 54 | if ((multiTimer[i].count == multiTimer[i].up) || (multiTimer[i].count == multiTimer[i].down)) 55 | { 56 | multiTimer[i].delta = -multiTimer[i].delta; 57 | } 58 | } 59 | } 60 | } 61 | 62 | public: 63 | PatternSpiral() { 64 | name = (char *)"Spiral"; 65 | } 66 | 67 | void start() { 68 | // set all counting directions positive for the beginning 69 | for (int i = 0; i < timers; i++) multiTimer[i].delta = 1; 70 | 71 | // set range (up/down), speed (takt=ms between steps) and starting point of all oszillators 72 | 73 | unsigned long now = millis(); 74 | 75 | multiTimer[0].lastMillis = now; 76 | multiTimer[0].takt = 42; //x1 77 | multiTimer[0].up = MATRIX_WIDTH - 1; 78 | multiTimer[0].down = 0; 79 | multiTimer[0].count = 0; 80 | 81 | multiTimer[1].lastMillis = now; 82 | multiTimer[1].takt = 55; //y1 83 | multiTimer[1].up = MATRIX_HEIGHT - 1; 84 | multiTimer[1].down = 0; 85 | multiTimer[1].count = 0; 86 | 87 | multiTimer[2].lastMillis = now; 88 | multiTimer[2].takt = 3; //color 89 | multiTimer[2].up = 255; 90 | multiTimer[2].down = 0; 91 | multiTimer[2].count = 0; 92 | 93 | multiTimer[3].lastMillis = now; 94 | multiTimer[3].takt = 71; //x2 95 | multiTimer[3].up = MATRIX_WIDTH - 1; 96 | multiTimer[3].down = 0; 97 | multiTimer[3].count = 0; 98 | 99 | multiTimer[4].lastMillis = now; 100 | multiTimer[4].takt = 89; //y2 101 | multiTimer[4].up = MATRIX_HEIGHT - 1; 102 | multiTimer[4].down = 0; 103 | multiTimer[4].count = 0; 104 | } 105 | 106 | unsigned int drawFrame() { 107 | // manage the Oszillators 108 | UpdateTimers(); 109 | 110 | // draw just a line defined by 5 oszillators 111 | effects.BresenhamLine( 112 | multiTimer[3].count, // x1 113 | multiTimer[4].count, // y1 114 | multiTimer[0].count, // x2 115 | multiTimer[1].count, // y2 116 | multiTimer[2].count); // color 117 | 118 | // manipulate the screen buffer 119 | // with fixed parameters (could be oszillators too) 120 | // Params: center x, y, radius, scale color down 121 | // --> NOTE: Affects always a SQUARE with an odd length 122 | // effects.SpiralStream(15, 15, 10, 128); 123 | 124 | effects.SpiralStream(31, 15, 64, 128); // for 64 pixel wide matrix! 125 | // effects.SpiralStream(47, 15, 10, 128); // for 64 pixel wide matrix! 126 | 127 | // why not several times?! 128 | // effects.SpiralStream(16, 6, 6, 128); 129 | // effects.SpiralStream(10, 24, 10, 128); 130 | 131 | // increase the contrast 132 | effects.DimAll(250); effects.ShowFrame(); 133 | 134 | return 0; 135 | } 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Glowing Square 2 | 3 | This project is a purpose-built display based on a 64x32 LED matrix and an ESP32. The code can be easily adapted for other purposes, and includes code to fetch web requests, store config, etc. 4 | 5 | I have made three displays so far: one that shows the current London Tube departures for my local station with data from TfL, one that shows planes flying over my house with data from Flightradar24 based on [this project](https://github.com/GroundBreakingItem0/esp8266_plane_tracker), and one that shows network statistics for my Unifi-based home network. 6 | 7 | ![Photo](https://i.imgur.com/ZX31npw.jpg) 8 | 9 | Full photo album [here](https://imgur.com/a/xTvUx8F). 10 | 11 | ## Features 12 | 13 | * Fetches JSON data from an API at a given interval 14 | * Parses the JSON and displays it 15 | * Brightness controlled by MQTT 16 | * "Party Mode" / Screensaver mode, turned on and off by MQTT 17 | * WiFiManager-based hotspot for configuration 18 | 19 | ## Hardware Required 20 | * 64x32 P4 LED Matrix (from [here](https://www.aliexpress.com/store/group/P4-led-module/1848738_509034839.html?spm=a2g0o.detail.0.0.65cc64c7oVbRJF)) 21 | * D1 Mini 32 (any of [these](https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20200704011236&SearchText=mini+esp32)) 22 | * Optional: Brian Lough's Shield PCB (you can wire it yourself instead, but these are much neater) (from [here](https://www.tindie.com/products/brianlough/esp32-matrix-shield-mini-32/)) 23 | * 24V PSU (up to 35W per display) (I picked [this one](https://www.ebay.co.uk/itm/DC-5V-12V-24V-Universal-Regulated-Switching-Power-Supply-for-LED-Strip-CCTV-UK/162562112782) for 3 displays) 24 | * LM2596 Buck Converter to step down to 5V (from [here](https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20200704011644&SearchText=LM2596)) 25 | * Two-core cable, Wago connectors/screw connectors, etc. 26 | * 6x M3 12mm bolts, 16x 3mm short countersunk screws 27 | 28 | You can just use a 5V power supply instead, but 100W+ ones tend to have loud fans in them, which is annoying, whereas my 24V 120W PSU is completely silent. It also helps with voltage drop if you're using long cables. 29 | 30 | ## Enclosure 31 | 32 | See the files in the Enclosure folder for the STLs of the two 3D-printed parts of this project, as well as the full Fusion 360 model showing you how it all fits together and what wood is required for the project. 33 | 34 | ![Back view](https://i.imgur.com/OPJ0tCZ.jpg) 35 | 36 | ## Global Config Options 37 | 38 | These options are available across all three displays: 39 | 40 | * Hostname - what your device will show up in your router admin console as (can't contain spaces, etc) 41 | * MQTT Server - the IP or domain name of your MQTT server 42 | * MQTT Port - defaults to 1833 43 | * MQTT Username 44 | * MQTT Password 45 | 46 | ## MQTT Control 47 | 48 | Set the room name (in the format `living_room` for example) in the web config interface, along with your MQTT server and port, etc. This will become the base of the topic when combined with the `MQTT_NAME` of your device in `mqtt.h`. Then the device will: 49 | 50 | * Publish on `room_name/MQTT_NAME/mqtt` `connected` or `disconnected` as a last will and testament 51 | * Listen on `room_name/MQTT_NAME/in` for messages in JSON format (e.g. `{ "brightness": 160 }` and will fade to the new brightness 52 | * Listen on `room_name/state` for messages in JSON format (e.g. `{ "party_mode": "chill" }` (or `off` or `on`) 53 | 54 | ## Tube / London Bus 55 | 56 | Find your TfL Stop ID [here](https://api.tfl.gov.uk/swagger/ui/index.html?url=/swagger/docs/v1#!/StopPoint/StopPoint_Search). TfL treats tube stops and bus stops the same, so if you provide the correct route and stop ID, it will work for both. 57 | 58 | Config Options: 59 | 60 | * TfL Stop ID 61 | * TfL Route (e.g. `northern`, `circle`, `H91`, `9`), you can test your route [here](https://api.tfl.gov.uk/swagger/ui/index.html?url=/swagger/docs/v1#!/Line/Line_Arrivals) 62 | * Direction (options are `outbound`, `inbound`, or empty for both) 63 | 64 | ## Flights 65 | 66 | Use Google Maps or similar to find the longitude and latitude of the top left and bottom right points that define the area you want to monitor flights inside. 67 | 68 | Config Options: 69 | 70 | * Flight Area in the format `51.5672,51.4131,-0.4146,0.1107` (for example) 71 | 72 | ## Unifi 73 | 74 | Unlike the other two, this one requires a PHP script running on a web server (because Unifi needs 3 different API requests to fetch the info I wanted to display, and also Unifi returns JSON payloads that are too big to fit in the RAM of the ESP32). 75 | 76 | Install the `GlowingSquare/Unifi/web/` files on your PHP server, and rename the `config.example.php` to `config.php`, filling in the necessary details as outlined by the code comments. Test that your server is working by visiting it in a web browser with `?width=64` appended to the URL to check you can scrape data correctly. 77 | 78 | Config Options: 79 | 80 | * Script URL as set up above, e.g. `http://10.0.1.9/glowingsquare/?width=64` 81 | 82 | ## Other Notes 83 | 84 | This project was just started as a passtime during the 2020 COVID-19 lockdown as a bit of fun, happy to take questions but this isn't a long-term open source kinda deal, I'm just open-sourcing an already completed thing. 85 | 86 | People have asked me if I'll be selling these, and I'll consider it and come up with a rough price estimate. It's a lot easier if you don't bother with the nice enclosure, which takes roughly 30% of the cost. 87 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/tubeapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | tubeapi.h 14 | * 15 | */ 16 | 17 | // Include our TfL credentials 18 | #include "secret.h" 19 | 20 | // The TfL Station ID is saved into config, comes from here: https://api.tfl.gov.uk/swagger/ui/index.html?url=/swagger/docs/v1#!/StopPoint/StopPoint_Search 21 | // The TfL Route is saved into config, test it out here: https://api.tfl.gov.uk/swagger/ui/index.html?url=/swagger/docs/v1#!/Line/Line_Arrivals 22 | // The TfL direction is saved into config, options are "outbound", "inbound", or "" for both 23 | 24 | #define SHOW_PLATFORM // If you want to include the departure platform in the scrolling text 25 | 26 | // Struct to store the information about each 27 | // train departure 28 | struct Departure { 29 | int timeToStation; 30 | const char* towards; 31 | const char* platform; 32 | }; 33 | 34 | // This is what we'll store the processed departures in 35 | std::vector departures; 36 | 37 | // Keep track of any failed web requests 38 | int failed_attempts = 0; 39 | 40 | // Function that runs from loop() every 60 seconds 41 | int downloadTubeInfo() { 42 | 43 | Serial.print("Fetching info from Tfl... "); 44 | 45 | HTTPClient http; 46 | 47 | long start = millis(); 48 | 49 | // This is the API endpoint that we fetch new departures for our station from 50 | char requestURL[256]; 51 | sprintf(requestURL, "https://api.tfl.gov.uk/Line/%s/Arrivals/%s?direction=%s&app_key=%s&app_id=%s", tfl_route, tfl_station_id, tfl_direction, TFL_APP_KEY, TFL_APP_ID); 52 | 53 | // Fetch the data from the server 54 | http.begin(requestURL); 55 | int httpCode = http.GET(); 56 | 57 | Serial.printf("took %ims... ", millis() - start); 58 | 59 | // Check that the server gave a valid response 60 | // Check that the server gave a valid response 61 | if (httpCode != 200) { 62 | Serial.printf("Failed to get info with HTTP Code %i\n", httpCode); // Code -11 means the request timed out 63 | 64 | // Mark us as offline so the little icon will be drawn next time 65 | failed_attempts++; 66 | return false; 67 | 68 | } else { 69 | // All is good 70 | if (failed_attempts > 0) 71 | displayOnline(); 72 | 73 | failed_attempts = 0; 74 | } 75 | 76 | 77 | String payload = http.getString(); 78 | 79 | if (payload.length() == 0) { 80 | 81 | // Sometimes there will just be no departures, cos the station is closed etc. 82 | Serial.println("No data received from TfL"); 83 | return false; 84 | } else { 85 | Serial.printf("Got data of length %i\n", payload.length()); 86 | } 87 | 88 | // Close the HTTPClient to free memory 89 | http.end(); 90 | 91 | // Remove the previous departures 92 | departures.clear(); 93 | 94 | /* 95 | * Because the JSON response from TfL can be and absolute chonker sometimes 96 | * (especially if you want to see departures in both directions), it's too 97 | * big to fit into RAM. To handle this, we can use a JSON filter 98 | * to only process the data we're interested in. 99 | * In this case that's the below parameters: 100 | */ 101 | StaticJsonDocument<160> filter; 102 | filter[0]["lineName"] = true; 103 | filter[0]["platformName"] = true; 104 | // filter[0]["currentLocation"] = true; // if you want to know where exactly the train is 105 | filter[0]["timeToStation"] = true; 106 | filter[0]["towards"] = true; 107 | 108 | // It's a chonky JSON document 109 | StaticJsonDocument<2048> json; 110 | deserializeJson(json, payload, DeserializationOption::Filter(filter)); 111 | 112 | // Loop over the returned entries and insert them into the vector list 113 | for (JsonVariantConst v : json.as()) { 114 | departures.push_back({v["timeToStation"], v["towards"], v["platformName"]}); 115 | } 116 | 117 | Serial.printf("Downloaded %i items from TfL\n", departures.size()); 118 | 119 | // Sort the vector list by ascending arrival time 120 | // (I don't know why TfL don't do this for us but oh well) 121 | std::sort(departures.begin(), departures.end(), [](const Departure &a, const Departure &b) { 122 | return a.timeToStation < b.timeToStation; 123 | }); 124 | 125 | } 126 | 127 | void displayTubeInfo() { 128 | 129 | // Loop over the four possible slots on the display 130 | for (int i = 0; i < 4; i++) { 131 | 132 | // If this row has no matching departure entry 133 | // then clear the row and skip 134 | if (i >= departures.size()) { 135 | fillBlankRow(i*8); 136 | break; 137 | } 138 | 139 | Serial.print("%%%"); 140 | Serial.println(departures[i].towards); 141 | 142 | // Convert seconds to minutes and format it nicely 143 | char formattedMins[10]; 144 | sprintf(formattedMins, "%im", departures[i].timeToStation / 60); 145 | 146 | Serial.printf("%s %s %s\n", formattedMins, departures[i].towards, departures[i].platform); 147 | 148 | // Append the platform name to the displayed text if required 149 | #ifdef SHOW_PLATFORM 150 | String scrollingText = (String)departures[i].towards + " " + (String)departures[i].platform; 151 | #else 152 | String scrollingText = (String)departures[i].towards 153 | #endif 154 | 155 | // Draw all of our data to the display 156 | drawStaticAndScrollingText(i*8, 40, formattedMins, scrollingText, 255, 80, 0, 150, 150, 150); 157 | 158 | // Wait before doing the next one 159 | delay(1000); 160 | 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/Patterns/Patterns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Patterns_H 24 | #define Patterns_H 25 | 26 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 27 | 28 | #include "Vector.h" 29 | #include "Boid.h" 30 | //#include "Attractor.h" 31 | 32 | /* 33 | * Note from mrfaptastic: 34 | * 35 | * Commented out patterns are due to the fact they either didn't work properly with a non-square display, 36 | * or from my personal opinion, are crap. 37 | */ 38 | 39 | #include "PatternWave.h" 40 | #include "PatternFlock.h" 41 | #include "PatternSnake.h" 42 | #include "PatternSimplexNoise.h" 43 | #include "PatternSpiral.h" 44 | 45 | class Patterns : public Playlist { 46 | private: 47 | 48 | PatternWave wave; 49 | PatternFlock flock; 50 | PatternSnake snake; 51 | PatternSpiral spiral; 52 | PatternSimplexNoise simplexNoise; 53 | 54 | int currentIndex = 0; 55 | Drawable* currentItem; 56 | 57 | int getCurrentIndex() { 58 | return currentIndex; 59 | } 60 | 61 | //const static int PATTERN_COUNT = 37; 62 | 63 | const static int PATTERN_COUNT = 5; 64 | 65 | Drawable* shuffledItems[PATTERN_COUNT]; 66 | 67 | Drawable* items[PATTERN_COUNT] = { 68 | &simplexNoise, // 17 - cool! 69 | &wave, // 18 ok 70 | &flock, // works 71 | &snake, // ok 72 | &spiral, // ok 73 | }; 74 | 75 | public: 76 | Patterns() { 77 | // add the items to the shuffledItems array 78 | for (int a = 0; a < PATTERN_COUNT; a++) { 79 | shuffledItems[a] = items[a]; 80 | } 81 | 82 | shuffleItems(); 83 | 84 | this->currentItem = items[0]; 85 | this->currentItem->start(); 86 | } 87 | 88 | char* Drawable::name = (char *)"Patterns"; 89 | 90 | void stop() { 91 | if (currentItem) 92 | currentItem->stop(); 93 | } 94 | 95 | void start() { 96 | if (currentItem) 97 | currentItem->start(); 98 | } 99 | 100 | void move(int step) { 101 | currentIndex += step; 102 | 103 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 104 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 105 | 106 | if (effects.paletteIndex == effects.RandomPaletteIndex) 107 | effects.RandomPalette(); 108 | 109 | moveTo(currentIndex); 110 | 111 | //if (!isTimeAvailable && currentItem == &analogClock) 112 | // move(step); 113 | } 114 | 115 | void moveRandom(int step) { 116 | currentIndex += step; 117 | 118 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 119 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 120 | 121 | if (effects.paletteIndex == effects.RandomPaletteIndex) 122 | effects.RandomPalette(); 123 | 124 | if (currentItem) 125 | currentItem->stop(); 126 | 127 | currentItem = shuffledItems[currentIndex]; 128 | 129 | if (currentItem) 130 | currentItem->start(); 131 | 132 | // if (!isTimeAvailable && currentItem == &analogClock) 133 | // moveRandom(step); 134 | } 135 | 136 | void shuffleItems() { 137 | for (int a = 0; a < PATTERN_COUNT; a++) 138 | { 139 | int r = random(a, PATTERN_COUNT); 140 | Drawable* temp = shuffledItems[a]; 141 | shuffledItems[a] = shuffledItems[r]; 142 | shuffledItems[r] = temp; 143 | } 144 | } 145 | 146 | 147 | unsigned int drawFrame() { 148 | return currentItem->drawFrame(); 149 | } 150 | 151 | void listPatterns() { 152 | Serial.println(F("{")); 153 | Serial.print(F(" \"count\": ")); 154 | Serial.print(PATTERN_COUNT); 155 | Serial.println(","); 156 | Serial.println(F(" \"results\": [")); 157 | 158 | for (int i = 0; i < PATTERN_COUNT; i++) { 159 | Serial.print(F(" \"")); 160 | Serial.print(i, DEC); 161 | Serial.print(F(": ")); 162 | Serial.print(items[i]->name); 163 | if (i == PATTERN_COUNT - 1) 164 | Serial.println(F("\"")); 165 | else 166 | Serial.println(F("\",")); 167 | } 168 | 169 | Serial.println(" ]"); 170 | Serial.println("}"); 171 | } 172 | 173 | char * getCurrentPatternName() 174 | { 175 | return currentItem->name; 176 | } 177 | 178 | void moveTo(int index) { 179 | if (currentItem) 180 | currentItem->stop(); 181 | 182 | currentIndex = index; 183 | 184 | currentItem = items[currentIndex]; 185 | 186 | if (currentItem) 187 | currentItem->start(); 188 | } 189 | 190 | bool setPattern(String name) { 191 | for (int i = 0; i < PATTERN_COUNT; i++) { 192 | if (name.compareTo(items[i]->name) == 0) { 193 | moveTo(i); 194 | return true; 195 | } 196 | } 197 | 198 | return false; 199 | } 200 | 201 | 202 | bool setPattern(int index) { 203 | if (index >= PATTERN_COUNT || index < 0) 204 | return false; 205 | 206 | moveTo(index); 207 | 208 | return true; 209 | } 210 | }; 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /GlowingSquare_Unifi/Patterns/Patterns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Patterns_H 24 | #define Patterns_H 25 | 26 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 27 | 28 | #include "Vector.h" 29 | #include "Boid.h" 30 | //#include "Attractor.h" 31 | 32 | /* 33 | * Note from mrfaptastic: 34 | * 35 | * Commented out patterns are due to the fact they either didn't work properly with a non-square display, 36 | * or from my personal opinion, are crap. 37 | */ 38 | 39 | #include "PatternWave.h" 40 | #include "PatternFlock.h" 41 | #include "PatternSnake.h" 42 | #include "PatternSimplexNoise.h" 43 | #include "PatternSpiral.h" 44 | 45 | class Patterns : public Playlist { 46 | private: 47 | 48 | PatternWave wave; 49 | PatternFlock flock; 50 | PatternSnake snake; 51 | PatternSpiral spiral; 52 | PatternSimplexNoise simplexNoise; 53 | 54 | int currentIndex = 0; 55 | Drawable* currentItem; 56 | 57 | int getCurrentIndex() { 58 | return currentIndex; 59 | } 60 | 61 | //const static int PATTERN_COUNT = 37; 62 | 63 | const static int PATTERN_COUNT = 5; 64 | 65 | Drawable* shuffledItems[PATTERN_COUNT]; 66 | 67 | Drawable* items[PATTERN_COUNT] = { 68 | &simplexNoise, // 17 - cool! 69 | &wave, // 18 ok 70 | &flock, // works 71 | &snake, // ok 72 | &spiral, // ok 73 | }; 74 | 75 | public: 76 | Patterns() { 77 | // add the items to the shuffledItems array 78 | for (int a = 0; a < PATTERN_COUNT; a++) { 79 | shuffledItems[a] = items[a]; 80 | } 81 | 82 | shuffleItems(); 83 | 84 | this->currentItem = items[0]; 85 | this->currentItem->start(); 86 | } 87 | 88 | char* Drawable::name = (char *)"Patterns"; 89 | 90 | void stop() { 91 | if (currentItem) 92 | currentItem->stop(); 93 | } 94 | 95 | void start() { 96 | if (currentItem) 97 | currentItem->start(); 98 | } 99 | 100 | void move(int step) { 101 | currentIndex += step; 102 | 103 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 104 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 105 | 106 | if (effects.paletteIndex == effects.RandomPaletteIndex) 107 | effects.RandomPalette(); 108 | 109 | moveTo(currentIndex); 110 | 111 | //if (!isTimeAvailable && currentItem == &analogClock) 112 | // move(step); 113 | } 114 | 115 | void moveRandom(int step) { 116 | currentIndex += step; 117 | 118 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 119 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 120 | 121 | if (effects.paletteIndex == effects.RandomPaletteIndex) 122 | effects.RandomPalette(); 123 | 124 | if (currentItem) 125 | currentItem->stop(); 126 | 127 | currentItem = shuffledItems[currentIndex]; 128 | 129 | if (currentItem) 130 | currentItem->start(); 131 | 132 | // if (!isTimeAvailable && currentItem == &analogClock) 133 | // moveRandom(step); 134 | } 135 | 136 | void shuffleItems() { 137 | for (int a = 0; a < PATTERN_COUNT; a++) 138 | { 139 | int r = random(a, PATTERN_COUNT); 140 | Drawable* temp = shuffledItems[a]; 141 | shuffledItems[a] = shuffledItems[r]; 142 | shuffledItems[r] = temp; 143 | } 144 | } 145 | 146 | 147 | unsigned int drawFrame() { 148 | return currentItem->drawFrame(); 149 | } 150 | 151 | void listPatterns() { 152 | Serial.println(F("{")); 153 | Serial.print(F(" \"count\": ")); 154 | Serial.print(PATTERN_COUNT); 155 | Serial.println(","); 156 | Serial.println(F(" \"results\": [")); 157 | 158 | for (int i = 0; i < PATTERN_COUNT; i++) { 159 | Serial.print(F(" \"")); 160 | Serial.print(i, DEC); 161 | Serial.print(F(": ")); 162 | Serial.print(items[i]->name); 163 | if (i == PATTERN_COUNT - 1) 164 | Serial.println(F("\"")); 165 | else 166 | Serial.println(F("\",")); 167 | } 168 | 169 | Serial.println(" ]"); 170 | Serial.println("}"); 171 | } 172 | 173 | char * getCurrentPatternName() 174 | { 175 | return currentItem->name; 176 | } 177 | 178 | void moveTo(int index) { 179 | if (currentItem) 180 | currentItem->stop(); 181 | 182 | currentIndex = index; 183 | 184 | currentItem = items[currentIndex]; 185 | 186 | if (currentItem) 187 | currentItem->start(); 188 | } 189 | 190 | bool setPattern(String name) { 191 | for (int i = 0; i < PATTERN_COUNT; i++) { 192 | if (name.compareTo(items[i]->name) == 0) { 193 | moveTo(i); 194 | return true; 195 | } 196 | } 197 | 198 | return false; 199 | } 200 | 201 | 202 | bool setPattern(int index) { 203 | if (index >= PATTERN_COUNT || index < 0) 204 | return false; 205 | 206 | moveTo(index); 207 | 208 | return true; 209 | } 210 | }; 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /GlowingSquare_Flight/Patterns/Patterns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Patterns_H 24 | #define Patterns_H 25 | 26 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 27 | 28 | #include "Vector.h" 29 | #include "Boid.h" 30 | //#include "Attractor.h" 31 | 32 | /* 33 | * Note from mrfaptastic: 34 | * 35 | * Commented out patterns are due to the fact they either didn't work properly with a non-square display, 36 | * or from my personal opinion, are crap. 37 | */ 38 | 39 | #include "PatternWave.h" 40 | #include "PatternFlock.h" 41 | #include "PatternSnake.h" 42 | #include "PatternSimplexNoise.h" 43 | #include "PatternSpiral.h" 44 | 45 | class Patterns : public Playlist { 46 | private: 47 | 48 | PatternWave wave; 49 | PatternFlock flock; 50 | PatternSnake snake; 51 | PatternSpiral spiral; 52 | PatternSimplexNoise simplexNoise; 53 | 54 | int currentIndex = 0; 55 | Drawable* currentItem; 56 | 57 | int getCurrentIndex() { 58 | return currentIndex; 59 | } 60 | 61 | //const static int PATTERN_COUNT = 37; 62 | 63 | const static int PATTERN_COUNT = 5; 64 | 65 | Drawable* shuffledItems[PATTERN_COUNT]; 66 | 67 | Drawable* items[PATTERN_COUNT] = { 68 | &simplexNoise, // 17 - cool! 69 | &wave, // 18 ok 70 | &flock, // works 71 | &snake, // ok 72 | &spiral, // ok 73 | }; 74 | 75 | public: 76 | Patterns() { 77 | // add the items to the shuffledItems array 78 | for (int a = 0; a < PATTERN_COUNT; a++) { 79 | shuffledItems[a] = items[a]; 80 | } 81 | 82 | shuffleItems(); 83 | 84 | this->currentItem = items[0]; 85 | this->currentItem->start(); 86 | } 87 | 88 | char* Drawable::name = (char *)"Patterns"; 89 | 90 | void stop() { 91 | if (currentItem) 92 | currentItem->stop(); 93 | } 94 | 95 | void start() { 96 | if (currentItem) 97 | currentItem->start(); 98 | } 99 | 100 | void move(int step) { 101 | currentIndex += step; 102 | 103 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 104 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 105 | 106 | if (effects.paletteIndex == effects.RandomPaletteIndex) 107 | effects.RandomPalette(); 108 | 109 | moveTo(currentIndex); 110 | 111 | //if (!isTimeAvailable && currentItem == &analogClock) 112 | // move(step); 113 | } 114 | 115 | void moveRandom(int step) { 116 | currentIndex += step; 117 | 118 | if (currentIndex >= PATTERN_COUNT) currentIndex = 0; 119 | else if (currentIndex < 0) currentIndex = PATTERN_COUNT - 1; 120 | 121 | if (effects.paletteIndex == effects.RandomPaletteIndex) 122 | effects.RandomPalette(); 123 | 124 | if (currentItem) 125 | currentItem->stop(); 126 | 127 | currentItem = shuffledItems[currentIndex]; 128 | 129 | if (currentItem) 130 | currentItem->start(); 131 | 132 | // if (!isTimeAvailable && currentItem == &analogClock) 133 | // moveRandom(step); 134 | } 135 | 136 | void shuffleItems() { 137 | for (int a = 0; a < PATTERN_COUNT; a++) 138 | { 139 | int r = random(a, PATTERN_COUNT); 140 | Drawable* temp = shuffledItems[a]; 141 | shuffledItems[a] = shuffledItems[r]; 142 | shuffledItems[r] = temp; 143 | } 144 | } 145 | 146 | 147 | unsigned int drawFrame() { 148 | return currentItem->drawFrame(); 149 | } 150 | 151 | void listPatterns() { 152 | Serial.println(F("{")); 153 | Serial.print(F(" \"count\": ")); 154 | Serial.print(PATTERN_COUNT); 155 | Serial.println(","); 156 | Serial.println(F(" \"results\": [")); 157 | 158 | for (int i = 0; i < PATTERN_COUNT; i++) { 159 | Serial.print(F(" \"")); 160 | Serial.print(i, DEC); 161 | Serial.print(F(": ")); 162 | Serial.print(items[i]->name); 163 | if (i == PATTERN_COUNT - 1) 164 | Serial.println(F("\"")); 165 | else 166 | Serial.println(F("\",")); 167 | } 168 | 169 | Serial.println(" ]"); 170 | Serial.println("}"); 171 | } 172 | 173 | char * getCurrentPatternName() 174 | { 175 | return currentItem->name; 176 | } 177 | 178 | void moveTo(int index) { 179 | if (currentItem) 180 | currentItem->stop(); 181 | 182 | currentIndex = index; 183 | 184 | currentItem = items[currentIndex]; 185 | 186 | if (currentItem) 187 | currentItem->start(); 188 | } 189 | 190 | bool setPattern(String name) { 191 | for (int i = 0; i < PATTERN_COUNT; i++) { 192 | if (name.compareTo(items[i]->name) == 0) { 193 | moveTo(i); 194 | return true; 195 | } 196 | } 197 | 198 | return false; 199 | } 200 | 201 | 202 | bool setPattern(int index) { 203 | if (index >= PATTERN_COUNT || index < 0) 204 | return false; 205 | 206 | moveTo(index); 207 | 208 | return true; 209 | } 210 | }; 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /GlowingSquare_Tube/display.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * _ ______ 5 | /\ | | | ____| 6 | / \ | | _____ __ | |__ ___ _ __ ___ _ _ 7 | / /\ \ | |/ _ \ \/ / | __/ _ \| '__/ _ \ | | | 8 | / ____ \| | __/> < | | | (_) | | | __/ |_| | 9 | /_/ \_\_|\___/_/\_\ |_| \___/|_| \___|\__, | 10 | __/ | 11 | Glowing Square: Tube Display |___/ 12 | For ESP32 13 | display.h 14 | * 15 | */ 16 | 17 | // We will use PxMatrix in double-buffer mode to allow us 18 | // to change many pixels and then update the display once in one go 19 | #define double_buffer true 20 | 21 | // Include must go here because double_buffer muse be defined first 22 | #include 23 | 24 | // 25 | hw_timer_t * timer = NULL; 26 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 27 | 28 | #define MATRIX_WIDTH 64 29 | #define MATRIX_HEIGHT 32 30 | 31 | // This defines the 'on' time of the display is us. The larger this number, 32 | // the brighter the display. If too large the ESP will crash 33 | #define DISPLAY_DRAW_TIME 70 // 30-70 is usually fine 34 | 35 | // Create our display with the correct pins 36 | // LAT=22, OE=2, A=19, B=23, C=18, D=5 (if there's an E it would be 15) 37 | PxMATRIX display(MATRIX_WIDTH, MATRIX_HEIGHT, 22, 2, 19, 23, 18, 5); 38 | 39 | // Display writer function from the example code 40 | void IRAM_ATTR display_updater(){ 41 | // Increment the counter and set the time of ISR 42 | portENTER_CRITICAL_ISR(&timerMux); 43 | display.display(DISPLAY_DRAW_TIME); 44 | portEXIT_CRITICAL_ISR(&timerMux); 45 | } 46 | 47 | // Draw a red pixel at the bottom right of the display if we're 48 | // offline, to show power is still on etc. 49 | void displayOffline() { 50 | 51 | display.clearDisplay(); 52 | display.drawPixel(MATRIX_WIDTH - 1, MATRIX_HEIGHT - 1, display.color565(255, 0, 0)); 53 | display.showBuffer(); 54 | display.copyBuffer(); 55 | 56 | } 57 | 58 | // Remove the red pixel at the bottom right of the display 59 | // because things are working now again 60 | void displayOnline() { 61 | display.drawPixel(MATRIX_WIDTH - 1, MATRIX_HEIGHT - 1, display.color565(0, 0, 0)); 62 | display.showBuffer(); 63 | display.copyBuffer(); 64 | } 65 | 66 | // Function to clear all the pixels for a given row of text 67 | // We have to do this otherwise the text always gets written over 68 | // the previous text, instead of replacing it 69 | void fillBlankRow(uint8_t ypos) { 70 | 71 | // Clear only the pixels on this part of the display 72 | for (int x = 0; x < MATRIX_WIDTH; x++) { 73 | for (int y = ypos; y < ypos + 8; y++) { 74 | display.drawPixel(x, y, display.color565(0, 0, 0 )); 75 | } 76 | } 77 | } 78 | 79 | void drawScrollingText(uint8_t ypos, int xpos, String scrollingText, uint8_t colorR_b, uint8_t colorG_b, uint8_t colorB_b) { 80 | // Write the scrolling text in its current position 81 | display.setTextColor(display.color565(colorR_b,colorG_b,colorB_b)); 82 | display.setCursor(xpos, ypos); 83 | display.println(scrollingText); 84 | } 85 | 86 | void drawStaticText(uint8_t ypos, uint16_t offset, String staticText, uint8_t colorR_a, uint8_t colorG_a, uint8_t colorB_a) { 87 | 88 | // Write black over the area the static text will take up 89 | for (int x = 0; x < offset; x++) { 90 | for (int y = ypos; y < ypos + 8; y++) { 91 | display.drawPixel(x, y, 0); 92 | } 93 | } 94 | 95 | // Draw the static text 96 | display.setCursor(0, ypos); 97 | display.setTextColor(display.color565(colorR_a,colorG_a,colorB_a)); 98 | display.println(staticText); 99 | 100 | } 101 | 102 | void drawStaticAndScrollingText(uint8_t ypos, unsigned long scroll_delay, String staticText, String scrollingText, uint8_t colorR_a, uint8_t colorG_a, uint8_t colorB_a, uint8_t colorR_b, uint8_t colorG_b, uint8_t colorB_b) { 103 | 104 | // Asuming 5 pixel average character width 105 | uint8_t characterWidth = 5; 106 | 107 | uint16_t scrollingTextLength = scrollingText.length(); 108 | uint16_t offset = staticText.length() * (characterWidth + 1); 109 | 110 | // Initial setup 111 | display.setTextSize(1); 112 | display.setRotation(0); 113 | 114 | // Each animation step of the scrolling 115 | for (int xpos = offset; xpos > -(MATRIX_WIDTH + scrollingTextLength * characterWidth) + 50; xpos--) { 116 | 117 | // Clear only the pixels on this part of the display 118 | fillBlankRow(ypos); 119 | 120 | drawScrollingText(ypos, xpos, scrollingText, colorR_b, colorG_b, colorB_b); 121 | 122 | drawStaticText(ypos, offset, staticText, colorR_a, colorG_a, colorB_a); 123 | 124 | // Draw the updates to the display 125 | display.showBuffer(); 126 | 127 | // Copy the updates to the second buffer to avoid flashing 128 | display.copyBuffer(); 129 | 130 | // Pause so we can set the speed of the animation 131 | delay(scroll_delay); 132 | yield(); 133 | 134 | } 135 | 136 | // Write the scrolling text again, once the scroll has finished 137 | // so that it persists while we're scrolling the other lines 138 | fillBlankRow(ypos); 139 | drawScrollingText(ypos, offset, scrollingText, colorR_b, colorG_b, colorB_b); 140 | drawStaticText(ypos, 0, staticText, colorR_a, colorG_a, colorB_a); 141 | 142 | // Send the final line to the display 143 | display.showBuffer(); 144 | display.copyBuffer(); 145 | 146 | } 147 | 148 | 149 | void setupDisplay() { 150 | 151 | // Start up our display with a 1/16 scan rate 152 | display.begin(16); 153 | 154 | // This is required for my SRYLED P4 display to work properly 155 | display.setMuxDelay(0,2,0,0,0); 156 | 157 | // Empty anything in the display buffer 158 | display.flushDisplay(); 159 | 160 | // We never want text to wrap in this project 161 | display.setTextWrap(false); 162 | 163 | display.setBrightness(currentDisplayBrightness); 164 | 165 | // More display setup bits taken from the double_buffer demo 166 | timer = timerBegin(0, 80, true); 167 | timerAttachInterrupt(timer, &display_updater, true); 168 | timerAlarmWrite(timer, 4000, true); 169 | timerAlarmEnable(timer); 170 | } 171 | 172 | void changeBrightnessBlocking(int fadeTime) { 173 | 174 | // Calculate how far we have to fade 175 | int change = targetDisplayBrightness - currentDisplayBrightness; 176 | 177 | // We have some fading to do 178 | if (change != 0) { 179 | 180 | // We fade at a 50Hz rate cos it makes the maths easier 181 | int step = change / (fadeTime / 20); 182 | 183 | // Prevent forever loops with 0 step 184 | if (step == 0 && change > 0) step = 1; 185 | if (step == 0 && change < 0) step = -1; 186 | 187 | Serial.printf("Fading from %i to %i brightness in steps of %i\n", currentDisplayBrightness, targetDisplayBrightness, step); 188 | 189 | while(currentDisplayBrightness != targetDisplayBrightness) { 190 | 191 | // This also supports steps being negative for fade downs 192 | currentDisplayBrightness += step; 193 | 194 | display.setBrightness(currentDisplayBrightness); 195 | 196 | // 50Hz there it is again 197 | delay(20); 198 | 199 | // In the case that the next step would take us past the desired target value 200 | if (abs(targetDisplayBrightness - currentDisplayBrightness) <= abs(step)) { 201 | 202 | // Stop there and set the display again 203 | currentDisplayBrightness = targetDisplayBrightness; 204 | display.setBrightness(currentDisplayBrightness); 205 | } 206 | 207 | } 208 | 209 | // Mark the fade as having completed 210 | currentDisplayBrightness = targetDisplayBrightness; 211 | 212 | Serial.println("Fade complete"); 213 | 214 | } 215 | 216 | } 217 | 218 | void changeBrightnessNonBlocking() { 219 | 220 | int change = targetDisplayBrightness - currentDisplayBrightness; 221 | 222 | if (change != 0) { 223 | 224 | if (change > 0) { 225 | currentDisplayBrightness += 1; 226 | } else if (change < 0) { 227 | currentDisplayBrightness -= 1; 228 | } 229 | 230 | display.setBrightness(currentDisplayBrightness); 231 | 232 | } 233 | 234 | } 235 | --------------------------------------------------------------------------------