2016-03-10 14:57:02 +01:00
/*
2018-10-06 20:09:10 +02:00
ESP8266 FastLED WebServer : https : //github.com/jasoncoon/esp8266-fastled-webserver
Copyright ( C ) 2015 - 2018 Jason Coon
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# define FASTLED_INTERRUPT_RETRY_COUNT 0
2016-12-18 23:02:44 +01:00
# include <FastLED.h>
2016-03-10 14:57:02 +01:00
FASTLED_USING_NAMESPACE
extern " C " {
# include "user_interface.h"
}
# include <ESP8266WiFi.h>
# include <ESP8266WebServer.h>
2016-12-18 23:02:44 +01:00
# include <ESP8266HTTPUpdateServer.h>
2016-03-10 14:57:02 +01:00
# include <FS.h>
# include <EEPROM.h>
# include "GradientPalettes.h"
2020-02-01 09:39:15 +01:00
# include "Field.h"
2016-03-10 14:57:02 +01:00
2020-04-11 09:41:25 +02:00
# include <PubSubClient.h> //Include the MQTT Library
# include <ArduinoJson.h> //Include the JSON library for use with MQTT
2016-12-18 23:02:44 +01:00
2020-02-01 09:39:15 +01:00
/*######################## MAIN CONFIG ########################*/
# define DATA_PIN D4 // Should be GPIO02 on other boards like the NodeMCU
# define LED_TYPE WS2812B // You might also use a WS2811 or any other strip that is fastled compatible
# define COLOR_ORDER GRB // Change this if colors are swapped (in my case, red was swapped with green)
# define MILLI_AMPS 5000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA)
# define VOLTS 5 // Voltage of the Power Supply
# define LEAFCOUNT 12 // Amount of triangles
# define PIXELS_PER_LEAF 12 // Amount of LEDs inside 1x Tringle
const bool apMode = false ; // set to true if the esp8266 should open an access point
//#define SOUND_REACTIVE // Uncomment to enable the Sound reactive mode
# define SOUND_SENSOR_PIN A0 // An Analog sensor should be connected to an analog pin
# define SENSOR_TYPE 1 // 0: Dumb Sensors, 1: MAX4466 Sound Sensor, 2: MAX9814 Sound Sensor
# define HOSTNAME "Nanoleafs" // Name that appears in your network
# define CORRECTION UncorrectedColor // If colors are weird use TypicalLEDStrip
# define RANDOM_AUTOPLAY_PATTERN // if enabled the next pattern for autoplay is choosen at random,
// if commented out patterns will play in order
# define ENABLE_ALEXA_SUPPORT // Espalexa library required
2020-04-11 09:41:25 +02:00
# define ENABLE_MQTT_SUPPORT // Enable MQTT library support
# define MQTT_TOPIC "homeassistant / light / nanoleafs" // MQTT Topic to Publish to (Home Assistant)
# define MQTT_TOPIC_SET "homeassistant / light / nanoleafs / set" // MQTT Topic to subscribe to (Home Assistant)
# define MQTT_MAX_PACKET_SIZE 1024
# define MQTT_MAX_TRANSFER_SIZE 1024
2020-02-01 09:39:15 +01:00
/*######################## MAIN CONFIG END ####################*/
/*############ Alexa Configuration ############*/
/* This part configures the devices that can be detected,
* by your Amazon Alexa device . In order to Connect the device ,
* open http : //ip_of_the_esp8266/alexa in your browser.
* Afterwards tell say " Alexa, discover devices " to your device ,
* after around 30 seconds it should respond with the new devices
* it has detected .
*
* In order to be able to control mutliple parameters of the nanoleafs ,
* the code creates multiple devices .
*
* To add those extra devices remove the two " // " in front of the ,
* defines below .
*/
# ifdef ENABLE_ALEXA_SUPPORT
# define ALEXA_DEVICE_NAME "Nanoleafs"
# define AddAutoplayDevice "Nanoleafs Autoplay"
# define AddStrobeDevice "Nanoleafs Strobe"
# define AddSpecificPatternDevice "Nanoleafs Party"
# ifdef AddSpecificPatternDevice
# define SpecificPattern 1 // Parameter defines what pattern gets executed
# endif
# endif // ENABLE_ALEXA_SUPPORT
/*########## Alexa Configuration END ##########*/
2020-04-11 09:41:25 +02:00
/*########### MQTT Configuration ##################*/
const char * mqttServer = " homeassistant.local " ;
const int mqttPort = 1883 ;
// For the user / password check the Secrets.h file and append at the end of it.
// const char* mqttUser = "YourMqttUser";
// const char* mqttPassword = "YourMqttUserPassword";
/*########### MQTT Configuration END ##################*/
2016-12-18 23:02:44 +01:00
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
ESP8266WebServer webServer ( 80 ) ;
2018-10-06 20:09:10 +02:00
//WebSocketsServer webSocketsServer = WebSocketsServer(81);
2016-12-18 23:02:44 +01:00
ESP8266HTTPUpdateServer httpUpdateServer ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
# include "FSBrowser.h"
2020-02-01 09:39:15 +01:00
# define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
2019-01-13 16:45:50 +01:00
# define NUM_LEDS (PIXELS_PER_LEAF * LEAFCOUNT)
2020-02-01 09:39:15 +01:00
# define FRAMES_PER_SECOND 120 // here you can control the speed. With the Access Point / Web Server the animations run a bit slower.
# define SOUND_REACTIVE_FPS 120
2018-10-06 20:09:10 +02:00
# include "Secrets.h" // this file is intentionally not included in the sketch, so nobody accidentally commits their secret information.
// create a Secrets.h file with the following:
// AP mode password
// const char WiFiAPPSK[] = "your-password";
// Wi-Fi network to connect to (if not in AP mode)
// char* ssid = "your-ssid";
// char* password = "your-password";
2016-03-10 14:57:02 +01:00
2020-02-01 09:39:15 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
# include <Espalexa.h>
void mainAlexaEvent ( EspalexaDevice * ) ;
Espalexa espalexa ;
ESP8266WebServer webServer2 ( 80 ) ;
EspalexaDevice * alexa_main ;
# endif // ENABLE_ALEXA_SUPPORT
2016-03-10 14:57:02 +01:00
CRGB leds [ NUM_LEDS ] ;
const uint8_t brightnessCount = 5 ;
2020-02-01 09:39:15 +01:00
uint8_t brightnessMap [ brightnessCount ] = { 5 , 32 , 64 , 128 , 255 } ;
2016-12-18 23:02:44 +01:00
uint8_t brightnessIndex = 0 ;
2016-03-10 14:57:02 +01:00
2020-02-01 09:39:15 +01:00
char vals [ 4 + LEAFCOUNT * 5 ] [ 4 ] = { " " } ;
uint8_t breathe = 0 ; // value for starting custom pattern
uint8_t breathe_dir = 1 ; // 1== rising
char cpattern [ 500 ] = " " ;
uint8_t allLeafs = 1 ; // Sets if all leafs should get the same color
uint8_t selectedLeaf = 1 ; // Sets position of leaf to color
// ten seconds per color palette makes a good demo
// 20-120 is better for deployment
uint8_t secondsPerPalette = 10 ;
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames. More cooling = shorter flames.
// Default 50, suggested range 20-100
uint8_t cooling = 3 ;
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire. Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
uint8_t sparking = 50 ;
uint8_t speed = 70 ;
2016-03-10 14:57:02 +01:00
///////////////////////////////////////////////////////////////////////
// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are. The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes [ ] ;
uint8_t gCurrentPaletteNumber = 0 ;
2019-01-13 16:45:50 +01:00
CRGBPalette16 gCurrentPalette ( CRGB : : Black ) ;
CRGBPalette16 gTargetPalette ( gGradientPalettes [ 0 ] ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
CRGBPalette16 IceColors_p = CRGBPalette16 ( CRGB : : Black , CRGB : : Blue , CRGB : : Aqua , CRGB : : White ) ;
2016-03-10 14:57:02 +01:00
uint8_t currentPatternIndex = 0 ; // Index number of which pattern is current
2016-12-18 23:02:44 +01:00
uint8_t autoplay = 0 ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
uint8_t autoplayDuration = 10 ;
unsigned long autoPlayTimeout = 0 ;
2016-03-10 14:57:02 +01:00
2017-02-18 20:48:33 +01:00
uint8_t currentPaletteIndex = 0 ;
2016-03-10 14:57:02 +01:00
uint8_t gHue = 0 ; // rotating "base color" used by many of the patterns
CRGB solidColor = CRGB : : Blue ;
2016-12-18 23:02:44 +01:00
// scale the brightness of all pixels down
void dimAll ( byte value )
{
for ( int i = 0 ; i < NUM_LEDS ; i + + ) {
leds [ i ] . nscale8 ( value ) ;
}
}
2019-01-13 16:45:50 +01:00
typedef void ( * Pattern ) ( ) ;
2016-12-18 23:02:44 +01:00
typedef Pattern PatternList [ ] ;
typedef struct {
Pattern pattern ;
String name ;
} PatternAndName ;
typedef PatternAndName PatternAndNameList [ ] ;
# include "Twinkles.h"
# include "TwinkleFOX.h"
// List of patterns to cycle through. Each is defined as a separate function below.
PatternAndNameList patterns = {
{ pride , " Pride " } ,
{ colorWaves , " Color Waves " } ,
2020-02-01 09:39:15 +01:00
{ rainbow , " Horizontal Rainbow " } ,
{ rainbowSolid , " Solid Rainbow " } ,
{ confetti , " Confetti " } ,
{ sinelon , " Sinelon " } ,
{ bpm , " Beat " } ,
{ juggle , " Juggle " } ,
{ fire , " Fire " } ,
{ water , " Water " } ,
{ strobe , " Strobe " } ,
{ rainbow_strobe , " Rainbow Strobe " } ,
2016-12-18 23:02:44 +01:00
// twinkle patterns
{ rainbowTwinkles , " Rainbow Twinkles " } ,
{ snowTwinkles , " Snow Twinkles " } ,
{ cloudTwinkles , " Cloud Twinkles " } ,
{ incandescentTwinkles , " Incandescent Twinkles " } ,
// TwinkleFOX patterns
{ retroC9Twinkles , " Retro C9 Twinkles " } ,
{ redWhiteTwinkles , " Red & White Twinkles " } ,
{ blueWhiteTwinkles , " Blue & White Twinkles " } ,
{ redGreenWhiteTwinkles , " Red, Green & White Twinkles " } ,
{ fairyLightTwinkles , " Fairy Light Twinkles " } ,
{ snow2Twinkles , " Snow 2 Twinkles " } ,
{ hollyTwinkles , " Holly Twinkles " } ,
{ iceTwinkles , " Ice Twinkles " } ,
{ partyTwinkles , " Party Twinkles " } ,
{ forestTwinkles , " Forest Twinkles " } ,
{ lavaTwinkles , " Lava Twinkles " } ,
{ fireTwinkles , " Fire Twinkles " } ,
{ cloud2Twinkles , " Cloud 2 Twinkles " } ,
{ oceanTwinkles , " Ocean Twinkles " } ,
2020-02-01 10:18:45 +01:00
{ showSolidColor , " Solid Color " }
2016-12-18 23:02:44 +01:00
} ;
const uint8_t patternCount = ARRAY_SIZE ( patterns ) ;
2017-02-18 20:48:33 +01:00
typedef struct {
CRGBPalette16 palette ;
2018-10-06 20:09:10 +02:00
String name ;
} PaletteAndName ;
2017-02-18 20:48:33 +01:00
typedef PaletteAndName PaletteAndNameList [ ] ;
const CRGBPalette16 palettes [ ] = {
RainbowColors_p ,
RainbowStripeColors_p ,
CloudColors_p ,
LavaColors_p ,
OceanColors_p ,
ForestColors_p ,
PartyColors_p ,
HeatColors_p
} ;
const uint8_t paletteCount = ARRAY_SIZE ( palettes ) ;
const String paletteNames [ paletteCount ] = {
" Rainbow " ,
" Rainbow Stripe " ,
" Cloud " ,
" Lava " ,
" Ocean " ,
2018-10-06 20:09:10 +02:00
" Forest " ,
2017-02-18 20:48:33 +01:00
" Party " ,
2018-10-06 20:09:10 +02:00
" Heat " ,
} ;
2017-02-18 20:48:33 +01:00
2016-12-18 23:02:44 +01:00
# include "Fields.h"
2016-03-10 14:57:02 +01:00
2020-04-11 09:41:25 +02:00
# ifdef ENABLE_MQTT_SUPPORT
WiFiClient espClient ;
PubSubClient mqttClient ( espClient ) ;
# endif
2016-12-18 23:02:44 +01:00
void setup ( ) {
2018-10-06 20:09:10 +02:00
WiFi . setSleepMode ( WIFI_NONE_SLEEP ) ;
2020-02-01 09:39:15 +01:00
# ifdef SOUND_REACTIVE
patterns [ patternCount - 2 ] = { soundReactive , " Sound Reactive " } ;
# endif // SOUND_REACTIVE
2016-03-10 14:57:02 +01:00
Serial . begin ( 115200 ) ;
delay ( 100 ) ;
Serial . setDebugOutput ( true ) ;
FastLED . addLeds < LED_TYPE , DATA_PIN , COLOR_ORDER > ( leds , NUM_LEDS ) ; // for WS2812 (Neopixel)
2020-02-01 09:39:15 +01:00
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS); // for APA102 (Dotstar)
2016-12-18 23:02:44 +01:00
FastLED . setDither ( false ) ;
2020-02-01 09:39:15 +01:00
FastLED . setCorrection ( CORRECTION ) ;
2016-03-10 14:57:02 +01:00
FastLED . setBrightness ( brightness ) ;
2020-02-01 09:39:15 +01:00
FastLED . setMaxPowerInVoltsAndMilliamps ( VOLTS , MILLI_AMPS ) ;
2016-12-18 23:02:44 +01:00
fill_solid ( leds , NUM_LEDS , CRGB : : Black ) ;
2016-03-10 14:57:02 +01:00
FastLED . show ( ) ;
EEPROM . begin ( 512 ) ;
loadSettings ( ) ;
2016-12-18 23:02:44 +01:00
FastLED . setBrightness ( brightness ) ;
2018-10-06 20:09:10 +02:00
// irReceiver.enableIRIn(); // Start the receiver
2016-03-10 14:57:02 +01:00
Serial . println ( ) ;
2019-01-13 16:45:50 +01:00
Serial . print ( F ( " Heap: " ) ) ; Serial . println ( system_get_free_heap_size ( ) ) ;
Serial . print ( F ( " Boot Vers: " ) ) ; Serial . println ( system_get_boot_version ( ) ) ;
Serial . print ( F ( " CPU: " ) ) ; Serial . println ( system_get_cpu_freq ( ) ) ;
Serial . print ( F ( " SDK: " ) ) ; Serial . println ( system_get_sdk_version ( ) ) ;
Serial . print ( F ( " Chip ID: " ) ) ; Serial . println ( system_get_chip_id ( ) ) ;
Serial . print ( F ( " Flash ID: " ) ) ; Serial . println ( spi_flash_get_id ( ) ) ;
Serial . print ( F ( " Flash Size: " ) ) ; Serial . println ( ESP . getFlashChipRealSize ( ) ) ;
Serial . print ( F ( " Vcc: " ) ) ; Serial . println ( ESP . getVcc ( ) ) ;
2016-03-10 14:57:02 +01:00
Serial . println ( ) ;
2020-02-01 09:39:15 +01:00
# ifdef SOUND_REACTIVE
# if SENSOR_TYPE == 0
pinMode ( SOUND_SENSOR_PIN , INPUT ) ;
# endif
# endif // SOUND_REACTIVE
2016-03-10 14:57:02 +01:00
SPIFFS . begin ( ) ;
{
2018-10-06 20:09:10 +02:00
Serial . println ( " SPIFFS contents: " ) ;
2016-03-10 14:57:02 +01:00
Dir dir = SPIFFS . openDir ( " / " ) ;
while ( dir . next ( ) ) {
String fileName = dir . fileName ( ) ;
size_t fileSize = dir . fileSize ( ) ;
Serial . printf ( " FS File: %s, size: %s \n " , fileName . c_str ( ) , String ( fileSize ) . c_str ( ) ) ;
}
Serial . printf ( " \n " ) ;
}
2018-01-30 17:30:09 +01:00
if ( apMode )
{
WiFi . mode ( WIFI_AP ) ;
// Do a little work to get a unique-ish name. Append the
// last two bytes of the MAC (HEX'd) to "Thing-":
uint8_t mac [ WL_MAC_ADDR_LENGTH ] ;
WiFi . softAPmacAddress ( mac ) ;
String macID = String ( mac [ WL_MAC_ADDR_LENGTH - 2 ] , HEX ) +
2020-02-01 09:39:15 +01:00
String ( mac [ WL_MAC_ADDR_LENGTH - 1 ] , HEX ) ;
2018-01-30 17:30:09 +01:00
macID . toUpperCase ( ) ;
String AP_NameString = " ESP8266 Thing " + macID ;
char AP_NameChar [ AP_NameString . length ( ) + 1 ] ;
memset ( AP_NameChar , 0 , AP_NameString . length ( ) + 1 ) ;
for ( int i = 0 ; i < AP_NameString . length ( ) ; i + + )
AP_NameChar [ i ] = AP_NameString . charAt ( i ) ;
WiFi . softAP ( AP_NameChar , WiFiAPPSK ) ;
Serial . printf ( " Connect to Wi-Fi access point: %s \n " , AP_NameChar ) ;
2020-04-11 09:41:25 +02:00
Serial . println ( " and open http://192.168.4.1 in your browser \n " ) ;
2018-01-30 17:30:09 +01:00
}
else
{
WiFi . mode ( WIFI_STA ) ;
Serial . printf ( " Connecting to %s \n " , ssid ) ;
if ( String ( WiFi . SSID ( ) ) ! = String ( ssid ) ) {
2019-09-01 14:23:06 +02:00
WiFi . begin ( ssid , password ) ;
2020-02-01 09:39:15 +01:00
WiFi . hostname ( HOSTNAME ) ;
2018-01-30 17:30:09 +01:00
}
}
2016-12-18 23:02:44 +01:00
2020-02-01 09:39:15 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
# ifdef ALEXA_DEVICE_NAME
alexa_main = new EspalexaDevice ( ALEXA_DEVICE_NAME , mainAlexaEvent , EspalexaDeviceType : : color ) ;
# else
alexa_main = new EspalexaDevice ( HOSTNAME , mainAlexaEvent , EspalexaDeviceType : : color ) ;
# endif
espalexa . addDevice ( alexa_main ) ;
# ifdef AddAutoplayDevice
espalexa . addDevice ( AddAutoplayDevice , AlexaAutoplayEvent , EspalexaDeviceType : : onoff ) ; //non-dimmable device
# endif
# ifdef AddStrobeDevice
espalexa . addDevice ( AddStrobeDevice , AlexaStrobeEvent , EspalexaDeviceType : : color ) ; //non-dimmable device
# endif
# ifdef AddSpecificPatternDevice
espalexa . addDevice ( AddSpecificPatternDevice , AlexaSpecificEvent , EspalexaDeviceType : : onoff ) ; //non-dimmable device
# endif
webServer . onNotFound ( [ ] ( ) {
if ( ! espalexa . handleAlexaApiCall ( webServer . uri ( ) , webServer . arg ( 0 ) ) ) //if you don't know the URI, ask espalexa whether it is an Alexa control request
{
//whatever you want to do with 404s
webServer . send ( 404 , " text/plain " , " Not found " ) ;
}
} ) ;
webServer . on ( " /alexa " , HTTP_GET , [ ] ( ) {
String h = " <font face='arial'><h1> Alexa pairing mode</h1> " ;
h + = " <h2>Procedure: </h3> " ;
h + = " The webserver will reboot and the UI won't be available.<br> " ;
h + = " <b>Now. Say to Alexa: 'Alexa, discover devices'.<b><br><br> " ;
h + = " Alexa should tell you that it found a new device, if it did reset the esp8266 to return to the normal mode.</font> " ;
webServer . send ( 200 , " text/html " , h ) ;
delay ( 100 ) ;
webServer . stop ( ) ;
delay ( 500 ) ;
webServer . close ( ) ;
delay ( 500 ) ;
webServer2 . onNotFound ( [ ] ( ) {
if ( ! espalexa . handleAlexaApiCall ( webServer2 . uri ( ) , webServer2 . arg ( 0 ) ) ) //if you don't know the URI, ask espalexa whether it is an Alexa control request
{
//whatever you want to do with 404s
webServer2 . send ( 404 , " text/plain " , " Not found " ) ;
}
} ) ;
espalexa . begin ( & webServer2 ) ;
delay ( 100 ) ;
while ( 1 )
{
espalexa . loop ( ) ;
delay ( 1 ) ;
}
} ) ;
# endif
2016-12-18 23:02:44 +01:00
httpUpdateServer . setup ( & webServer ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
webServer . on ( " /all " , HTTP_GET , [ ] ( ) {
String json = getFieldsJson ( fields , fieldCount ) ;
webServer . send ( 200 , " text/json " , json ) ;
} ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
webServer . on ( " /fieldValue " , HTTP_GET , [ ] ( ) {
String name = webServer . arg ( " name " ) ;
String value = getFieldValue ( name , fields , fieldCount ) ;
webServer . send ( 200 , " text/json " , value ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /fieldValue " , HTTP_POST , [ ] ( ) {
String name = webServer . arg ( " name " ) ;
String value = webServer . arg ( " value " ) ;
String newValue = setFieldValue ( name , value , fields , fieldCount ) ;
webServer . send ( 200 , " text/json " , newValue ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /power " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
2016-03-10 14:57:02 +01:00
setPower ( value . toInt ( ) ) ;
2016-12-18 23:02:44 +01:00
sendInt ( power ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /cooling " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
cooling = value . toInt ( ) ;
broadcastInt ( " cooling " , cooling ) ;
sendInt ( cooling ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /sparking " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
sparking = value . toInt ( ) ;
broadcastInt ( " sparking " , sparking ) ;
sendInt ( sparking ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /speed " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
speed = value . toInt ( ) ;
broadcastInt ( " speed " , speed ) ;
sendInt ( speed ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /twinkleSpeed " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
twinkleSpeed = value . toInt ( ) ;
2018-10-06 20:09:10 +02:00
if ( twinkleSpeed < 0 ) twinkleSpeed = 0 ;
2016-12-18 23:02:44 +01:00
else if ( twinkleSpeed > 8 ) twinkleSpeed = 8 ;
broadcastInt ( " twinkleSpeed " , twinkleSpeed ) ;
sendInt ( twinkleSpeed ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /twinkleDensity " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
twinkleDensity = value . toInt ( ) ;
2018-10-06 20:09:10 +02:00
if ( twinkleDensity < 0 ) twinkleDensity = 0 ;
2016-12-18 23:02:44 +01:00
else if ( twinkleDensity > 8 ) twinkleDensity = 8 ;
broadcastInt ( " twinkleDensity " , twinkleDensity ) ;
sendInt ( twinkleDensity ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /solidColor " , HTTP_POST , [ ] ( ) {
String r = webServer . arg ( " r " ) ;
String g = webServer . arg ( " g " ) ;
String b = webServer . arg ( " b " ) ;
setSolidColor ( r . toInt ( ) , g . toInt ( ) , b . toInt ( ) ) ;
2020-02-03 16:40:16 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
2020-02-01 09:39:15 +01:00
alexa_main - > setColor ( r . toInt ( ) , g . toInt ( ) , b . toInt ( ) ) ;
2020-02-03 16:40:16 +01:00
# endif
2016-12-18 23:02:44 +01:00
sendString ( String ( solidColor . r ) + " , " + String ( solidColor . g ) + " , " + String ( solidColor . b ) ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /pattern " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
2020-02-01 09:39:15 +01:00
setPattern ( value . toInt ( ) ) ;
sendInt ( currentPatternIndex ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /patternName " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setPatternName ( value ) ;
sendInt ( currentPatternIndex ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2017-02-18 20:48:33 +01:00
webServer . on ( " /palette " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setPalette ( value . toInt ( ) ) ;
sendInt ( currentPaletteIndex ) ;
} ) ;
webServer . on ( " /paletteName " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setPaletteName ( value ) ;
sendInt ( currentPaletteIndex ) ;
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /brightness " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setBrightness ( value . toInt ( ) ) ;
2020-02-03 16:40:16 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
2020-02-01 09:39:15 +01:00
alexa_main - > setValue ( brightness ) ;
2020-02-03 16:40:16 +01:00
# endif
2016-12-18 23:02:44 +01:00
sendInt ( brightness ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /autoplay " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setAutoplay ( value . toInt ( ) ) ;
sendInt ( autoplay ) ;
2016-03-10 14:57:02 +01:00
} ) ;
2016-12-18 23:02:44 +01:00
webServer . on ( " /autoplayDuration " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setAutoplayDuration ( value . toInt ( ) ) ;
sendInt ( autoplayDuration ) ;
} ) ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
webServer . on ( " /allLeafs " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setAllLeafs ( value . toInt ( ) ) ;
sendInt ( allLeafs ) ;
} ) ;
webServer . on ( " /selectedLeaf " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
setSelectedLeaf ( value . toInt ( ) ) ;
sendInt ( selectedLeaf ) ;
} ) ;
2019-02-24 21:48:14 +01:00
webServer . on ( " /custom " , HTTP_POST , [ ] ( ) {
String value = webServer . arg ( " value " ) ;
Serial . println ( value ) ;
value . toCharArray ( cpattern , 500 ) ;
Serial . println ( value ) ;
sendString ( value ) ;
setPattern ( 30 ) ;
} ) ;
2016-12-18 23:02:44 +01:00
//list directory
webServer . on ( " /list " , HTTP_GET , handleFileList ) ;
//load editor
webServer . on ( " /edit " , HTTP_GET , [ ] ( ) {
if ( ! handleFileRead ( " /edit.htm " ) ) webServer . send ( 404 , " text/plain " , " FileNotFound " ) ;
} ) ;
//create file
webServer . on ( " /edit " , HTTP_PUT , handleFileCreate ) ;
//delete file
webServer . on ( " /edit " , HTTP_DELETE , handleFileDelete ) ;
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
webServer . on ( " /edit " , HTTP_POST , [ ] ( ) {
webServer . send ( 200 , " text/plain " , " " ) ;
} , handleFileUpload ) ;
webServer . serveStatic ( " / " , SPIFFS , " / " , " max-age=86400 " ) ;
2020-02-01 09:39:15 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
espalexa . begin ( & webServer ) ;
# endif
# ifndef ENABLE_ALEXA_SUPPORT
2016-12-18 23:02:44 +01:00
webServer . begin ( ) ;
2020-02-01 09:39:15 +01:00
# endif
2016-12-18 23:02:44 +01:00
Serial . println ( " HTTP web server started " ) ;
2018-10-06 20:09:10 +02:00
// webSocketsServer.begin();
// webSocketsServer.onEvent(webSocketEvent);
// Serial.println("Web socket server started");
2016-12-18 23:02:44 +01:00
autoPlayTimeout = millis ( ) + ( autoplayDuration * 1000 ) ;
}
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
void sendInt ( uint8_t value )
{
sendString ( String ( value ) ) ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
void sendString ( String value )
{
webServer . send ( 200 , " text/plain " , value ) ;
}
2016-03-12 18:28:33 +01:00
2016-12-18 23:02:44 +01:00
void broadcastInt ( String name , uint8_t value )
{
String json = " { \" name \" : \" " + name + " \" , \" value \" : " + String ( value ) + " } " ;
2018-10-06 20:09:10 +02:00
// webSocketsServer.broadcastTXT(json);
2016-12-18 23:02:44 +01:00
}
2016-03-12 18:28:33 +01:00
2016-12-18 23:02:44 +01:00
void broadcastString ( String name , String value )
{
String json = " { \" name \" : \" " + name + " \" , \" value \" : \" " + String ( value ) + " \" } " ;
2018-10-06 20:09:10 +02:00
// webSocketsServer.broadcastTXT(json);
2016-12-18 23:02:44 +01:00
}
2016-03-12 18:28:33 +01:00
2016-12-18 23:02:44 +01:00
void loop ( ) {
2020-04-11 09:41:25 +02:00
mqttClient . loop ( ) ;
2016-03-10 14:57:02 +01:00
// Add entropy to random number generator; we use a lot of it.
random16_add_entropy ( random ( 65535 ) ) ;
2018-10-06 20:09:10 +02:00
// dnsServer.processNextRequest();
// webSocketsServer.loop();
2020-02-03 16:40:16 +01:00
# ifdef ENABLE_ALEXA_SUPPORT
espalexa . loop ( ) ;
# else
2016-12-18 23:02:44 +01:00
webServer . handleClient ( ) ;
2020-02-03 16:40:16 +01:00
# endif
2018-10-06 20:09:10 +02:00
// handleIrInput();
2016-03-10 14:57:02 +01:00
if ( power = = 0 ) {
fill_solid ( leds , NUM_LEDS , CRGB : : Black ) ;
FastLED . show ( ) ;
2016-12-18 23:02:44 +01:00
// FastLED.delay(15);
2016-03-10 14:57:02 +01:00
return ;
}
2018-10-06 20:09:10 +02:00
static bool hasConnected = false ;
EVERY_N_SECONDS ( 1 ) {
if ( WiFi . status ( ) ! = WL_CONNECTED ) {
// Serial.printf("Connecting to %s\n", ssid);
hasConnected = false ;
}
else if ( ! hasConnected ) {
hasConnected = true ;
Serial . print ( " Connected! Open http:// " ) ;
Serial . print ( WiFi . localIP ( ) ) ;
Serial . println ( " in your browser " ) ;
}
}
2020-04-11 09:41:25 +02:00
static bool mqttConnected = false ;
EVERY_N_SECONDS ( 10 ) {
if ( ! mqttClient . connected ( ) ) {
mqttClient . setServer ( mqttServer , mqttPort ) ;
mqttClient . setCallback ( mqttCallback ) ;
mqttConnected = false ;
} else {
sendStatus ( ) ;
}
if ( ! mqttConnected ) {
mqttConnected = true ;
Serial . println ( " Connecting to MQTT... " ) ;
if ( mqttClient . connect ( HOSTNAME , mqttUser , mqttPassword ) ) {
Serial . println ( " connected \n " ) ;
Serial . println ( " Subscribing to MQTT Topics \n " ) ;
mqttClient . subscribe ( MQTT_TOPIC " /set " ) ;
StaticJsonDocument < 1024 > JSONencoder ;
JSONencoder [ " ~ " ] = MQTT_TOPIC ,
JSONencoder [ " name " ] = " Nanoleafs " ,
JSONencoder [ " device " ] [ " identifiers " ] = " livingroom_nanoleafs " ,
JSONencoder [ " device " ] [ " manufacturer " ] = " WD DIY " ,
JSONencoder [ " device " ] [ " model " ] = " 0.1 " ,
JSONencoder [ " device " ] [ " name " ] = " DIY Nanoleafs " ,
JSONencoder [ " state_topic " ] = " ~ " ,
JSONencoder [ " command_topic " ] = " ~/set " ,
JSONencoder [ " brightness " ] = true ,
JSONencoder [ " rgb " ] = true ,
JSONencoder [ " effect " ] = true ,
JSONencoder [ " uniq_id " ] = " livingroom_nanoleafs " ,
JSONencoder [ " schema " ] = " json " ;
JsonArray effect_list = JSONencoder . createNestedArray ( " effect_list " ) ;
for ( uint8_t i = 0 ; i < patternCount ; i + + ) {
effect_list . add ( patterns [ i ] . name ) ;
}
char JSONmessage [ 1024 ] ;
size_t n = serializeJson ( JSONencoder , JSONmessage ) ;
if ( mqttClient . beginPublish ( MQTT_TOPIC " /config " , n , true ) = = true ) {
Serial . println ( " Configuration Publishing Begun " ) ;
if ( mqttClient . print ( JSONmessage ) = = true ) {
Serial . println ( " Configuration Sent " ) ;
}
if ( mqttClient . endPublish ( ) = = true ) {
Serial . println ( " Configuration Publishing Finished " ) ;
}
} else {
Serial . println ( " Error sending Configuration " ) ;
}
} else {
Serial . print ( " failed with state " ) ;
Serial . print ( mqttClient . state ( ) ) ;
}
}
}
2016-03-10 14:57:02 +01:00
// EVERY_N_SECONDS(10) {
// Serial.print( F("Heap: ") ); Serial.println(system_get_free_heap_size());
// }
// change to a new cpt-city gradient palette
2019-01-13 16:45:50 +01:00
EVERY_N_SECONDS ( secondsPerPalette ) {
gCurrentPaletteNumber = addmod8 ( gCurrentPaletteNumber , 1 , gGradientPaletteCount ) ;
gTargetPalette = gGradientPalettes [ gCurrentPaletteNumber ] ;
2016-03-10 14:57:02 +01:00
}
2019-01-13 16:45:50 +01:00
EVERY_N_MILLISECONDS ( 80 ) {
2016-12-18 23:02:44 +01:00
// slowly blend the current palette to the next
2019-01-13 16:45:50 +01:00
nblendPaletteTowardPalette ( gCurrentPalette , gTargetPalette , 8 ) ;
2016-12-18 23:02:44 +01:00
gHue + + ; // slowly cycle the "base color" through the rainbow
2016-03-10 14:57:02 +01:00
}
2016-07-19 01:52:44 +02:00
2019-02-24 21:48:14 +01:00
EVERY_N_MILLIS_I ( thistimer , 128 - ( speed / 2 ) ) {
if ( breathe_dir = = 1 ) breathe + + ; else breathe - - ;
if ( breathe > = 255 ) breathe_dir = 0 ;
else if ( breathe < = 0 ) breathe_dir = 1 ;
//Serial.println(breathe);
}
thistimer . setPeriod ( 64 - ( speed / 4 ) ) ;
2016-12-18 23:02:44 +01:00
if ( autoplay & & ( millis ( ) > autoPlayTimeout ) ) {
2016-03-10 14:57:02 +01:00
adjustPattern ( true ) ;
2016-12-18 23:02:44 +01:00
autoPlayTimeout = millis ( ) + ( autoplayDuration * 1000 ) ;
2016-03-10 14:57:02 +01:00
}
// Call the current pattern function once, updating the 'leds' array
patterns [ currentPatternIndex ] . pattern ( ) ;
FastLED . show ( ) ;
// insert a delay to keep the framerate modest
2018-10-06 20:09:10 +02:00
FastLED . delay ( 1000 / FRAMES_PER_SECOND ) ;
2016-12-18 23:02:44 +01:00
}
2018-10-06 20:09:10 +02:00
//void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
//
// switch (type) {
// case WStype_DISCONNECTED:
// Serial.printf("[%u] Disconnected!\n", num);
// break;
//
// case WStype_CONNECTED:
// {
// IPAddress ip = webSocketsServer.remoteIP(num);
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
//
// // send message to client
// // webSocketsServer.sendTXT(num, "Connected");
// }
// break;
//
// case WStype_TEXT:
// Serial.printf("[%u] get Text: %s\n", num, payload);
//
// // send message to client
// // webSocketsServer.sendTXT(num, "message here");
//
// // send data to all connected clients
// // webSocketsServer.broadcastTXT("message here");
// break;
//
// case WStype_BIN:
// Serial.printf("[%u] get binary length: %u\n", num, length);
// hexdump(payload, length);
//
// // send message to client
// // webSocketsServer.sendBIN(num, payload, lenght);
// break;
// }
//}
2016-03-10 14:57:02 +01:00
2020-04-11 09:41:25 +02:00
void mqttCallback ( char * topic , byte * payload , unsigned int length ) {
StaticJsonDocument < 256 > doc ;
deserializeJson ( doc , payload , length ) ;
JsonObject obj = doc . as < JsonObject > ( ) ;
for ( JsonPair p : obj ) {
const char * key = p . key ( ) . c_str ( ) ;
JsonVariant v = p . value ( ) ;
String value = v . as < String > ( ) ; //Delete
Serial . println ( key ) ; //Delete
Serial . println ( value ) ; //Delete
if ( strcmp ( key , " state " ) = = 0 ) {
String val = v . as < String > ( ) ;
setPower ( ( val = = " ON " ) ? 1 : 0 ) ;
}
if ( strcmp ( key , " brightness " ) = = 0 ) {
int val = v . as < int > ( ) ;
setBrightness ( val ) ;
}
if ( strcmp ( key , " effect " ) = = 0 ) {
String val = v . as < String > ( ) ;
setPatternName ( val ) ;
}
if ( strcmp ( key , " color " ) = = 0 ) {
int cr , cb , cg ;
JsonObject val = v . as < JsonObject > ( ) ;
for ( JsonPair o : val ) {
const char * ckey = o . key ( ) . c_str ( ) ;
JsonVariant cv = o . value ( ) ;
if ( strcmp ( ckey , " r " ) = = 0 ) {
cr = cv . as < int > ( ) ;
}
if ( strcmp ( ckey , " g " ) = = 0 ) {
cg = cv . as < int > ( ) ;
}
if ( strcmp ( ckey , " b " ) = = 0 ) {
cb = cv . as < int > ( ) ;
}
}
setSolidColor ( cr , cg , cb ) ;
}
}
sendStatus ( ) ;
}
2019-01-13 16:45:50 +01:00
2020-04-11 09:41:25 +02:00
void sendStatus ( )
{
StaticJsonDocument < 128 > JSONencoder ;
JSONencoder [ " state " ] = ( power = = 1 ? " ON " : " OFF " ) ,
JSONencoder [ " brightness " ] = brightness ,
JSONencoder [ " effect " ] = patterns [ currentPatternIndex ] . name ,
JSONencoder [ " QoS " ] = 2 ;
char JSONmessage [ 128 ] ;
size_t n = serializeJson ( JSONencoder , JSONmessage ) ;
mqttClient . publish ( MQTT_TOPIC , JSONmessage , n , true ) ;
}
2016-03-10 14:57:02 +01:00
void loadSettings ( )
{
brightness = EEPROM . read ( 0 ) ;
currentPatternIndex = EEPROM . read ( 1 ) ;
if ( currentPatternIndex < 0 )
currentPatternIndex = 0 ;
else if ( currentPatternIndex > = patternCount )
currentPatternIndex = patternCount - 1 ;
byte r = EEPROM . read ( 2 ) ;
byte g = EEPROM . read ( 3 ) ;
byte b = EEPROM . read ( 4 ) ;
if ( r = = 0 & & g = = 0 & & b = = 0 )
{
}
else
{
solidColor = CRGB ( r , g , b ) ;
}
2016-12-18 23:02:44 +01:00
power = EEPROM . read ( 5 ) ;
autoplay = EEPROM . read ( 6 ) ;
autoplayDuration = EEPROM . read ( 7 ) ;
2017-02-18 20:48:33 +01:00
2017-02-22 01:53:15 +01:00
currentPaletteIndex = EEPROM . read ( 8 ) ;
2017-02-18 20:48:33 +01:00
if ( currentPaletteIndex < 0 )
currentPaletteIndex = 0 ;
else if ( currentPaletteIndex > = paletteCount )
currentPaletteIndex = paletteCount - 1 ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
void setPower ( uint8_t value )
2016-03-10 14:57:02 +01:00
{
2016-12-18 23:02:44 +01:00
power = value = = 0 ? 0 : 1 ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
EEPROM . write ( 5 , power ) ;
EEPROM . commit ( ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
broadcastInt ( " power " , power ) ;
}
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
void setAutoplay ( uint8_t value )
2018-10-06 20:09:10 +02:00
{
2016-12-18 23:02:44 +01:00
autoplay = value = = 0 ? 0 : 1 ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
EEPROM . write ( 6 , autoplay ) ;
EEPROM . commit ( ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
broadcastInt ( " autoplay " , autoplay ) ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
void setAutoplayDuration ( uint8_t value )
2016-03-10 14:57:02 +01:00
{
2016-12-18 23:02:44 +01:00
autoplayDuration = value ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
EEPROM . write ( 7 , autoplayDuration ) ;
EEPROM . commit ( ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
autoPlayTimeout = millis ( ) + ( autoplayDuration * 1000 ) ;
2016-03-10 14:57:02 +01:00
2016-12-18 23:02:44 +01:00
broadcastInt ( " autoplayDuration " , autoplayDuration ) ;
2016-03-10 14:57:02 +01:00
}
2019-01-13 16:45:50 +01:00
void setAllLeafs ( uint8_t value )
{
allLeafs = value = = 0 ? 0 : 1 ;
EEPROM . write ( 8 , allLeafs ) ;
EEPROM . commit ( ) ;
broadcastInt ( " allLeafs " , allLeafs ) ;
}
void setSelectedLeaf ( uint8_t value )
{
selectedLeaf = value ;
EEPROM . write ( 9 , selectedLeaf ) ;
EEPROM . commit ( ) ;
broadcastInt ( " selectedLeaf " , selectedLeaf ) ;
}
2016-03-10 14:57:02 +01:00
void setSolidColor ( CRGB color )
{
setSolidColor ( color . r , color . g , color . b ) ;
}
void setSolidColor ( uint8_t r , uint8_t g , uint8_t b )
{
solidColor = CRGB ( r , g , b ) ;
EEPROM . write ( 2 , r ) ;
2016-07-19 01:52:44 +02:00
EEPROM . write ( 3 , g ) ;
EEPROM . write ( 4 , b ) ;
2016-12-18 23:02:44 +01:00
EEPROM . commit ( ) ;
2016-03-10 14:57:02 +01:00
2019-02-24 21:48:14 +01:00
setPattern ( 29 ) ;
2016-12-18 23:02:44 +01:00
broadcastString ( " color " , String ( solidColor . r ) + " , " + String ( solidColor . g ) + " , " + String ( solidColor . b ) ) ;
2019-02-24 21:48:14 +01:00
FastLED . show ( ) ;
2016-03-10 14:57:02 +01:00
}
// increase or decrease the current pattern number, and wrap around at the ends
void adjustPattern ( bool up )
{
2020-02-01 09:39:15 +01:00
# ifdef RANDOM_AUTOPLAY_PATTERN
if ( autoplay = = 1 )
{
uint8_t lastpattern = currentPatternIndex ;
while ( currentPatternIndex = = lastpattern )
{
uint8_t newpattern = random8 ( 0 , patternCount - 2 ) ;
if ( newpattern ! = lastpattern ) currentPatternIndex = newpattern ;
}
}
# else // RANDOM_AUTOPLAY_PATTERN
2016-03-10 14:57:02 +01:00
if ( up )
currentPatternIndex + + ;
else
currentPatternIndex - - ;
2020-02-01 09:39:15 +01:00
# endif
if ( autoplay = = 0 )
{
if ( up )
currentPatternIndex + + ;
else
currentPatternIndex - - ;
}
2016-03-10 14:57:02 +01:00
// wrap around at the ends
if ( currentPatternIndex < 0 )
currentPatternIndex = patternCount - 1 ;
2020-02-01 09:39:15 +01:00
if ( currentPatternIndex > = ( patternCount - 1 ) )
2016-03-10 14:57:02 +01:00
currentPatternIndex = 0 ;
2017-02-18 20:48:33 +01:00
if ( autoplay = = 0 ) {
EEPROM . write ( 1 , currentPatternIndex ) ;
EEPROM . commit ( ) ;
}
2016-12-18 23:02:44 +01:00
broadcastInt ( " pattern " , currentPatternIndex ) ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
void setPattern ( uint8_t value )
2016-03-10 14:57:02 +01:00
{
2016-12-18 23:02:44 +01:00
if ( value > = patternCount )
2016-03-10 14:57:02 +01:00
value = patternCount - 1 ;
currentPatternIndex = value ;
2017-02-18 20:48:33 +01:00
if ( autoplay = = 0 ) {
EEPROM . write ( 1 , currentPatternIndex ) ;
EEPROM . commit ( ) ;
}
2016-12-18 23:02:44 +01:00
broadcastInt ( " pattern " , currentPatternIndex ) ;
}
void setPatternName ( String name )
{
2018-10-06 20:09:10 +02:00
for ( uint8_t i = 0 ; i < patternCount ; i + + ) {
if ( patterns [ i ] . name = = name ) {
2016-12-18 23:02:44 +01:00
setPattern ( i ) ;
break ;
}
}
2016-03-10 14:57:02 +01:00
}
2017-02-18 20:48:33 +01:00
void setPalette ( uint8_t value )
{
if ( value > = paletteCount )
value = paletteCount - 1 ;
currentPaletteIndex = value ;
2017-02-22 01:53:15 +01:00
EEPROM . write ( 8 , currentPaletteIndex ) ;
2017-02-18 20:48:33 +01:00
EEPROM . commit ( ) ;
broadcastInt ( " palette " , currentPaletteIndex ) ;
}
void setPaletteName ( String name )
{
2018-10-06 20:09:10 +02:00
for ( uint8_t i = 0 ; i < paletteCount ; i + + ) {
if ( paletteNames [ i ] = = name ) {
2017-02-18 20:48:33 +01:00
setPalette ( i ) ;
break ;
}
}
}
2016-03-10 14:57:02 +01:00
void adjustBrightness ( bool up )
{
2016-12-18 23:02:44 +01:00
if ( up & & brightnessIndex < brightnessCount - 1 )
2016-03-10 14:57:02 +01:00
brightnessIndex + + ;
2016-12-18 23:02:44 +01:00
else if ( ! up & & brightnessIndex > 0 )
2016-03-10 14:57:02 +01:00
brightnessIndex - - ;
brightness = brightnessMap [ brightnessIndex ] ;
FastLED . setBrightness ( brightness ) ;
EEPROM . write ( 0 , brightness ) ;
EEPROM . commit ( ) ;
2016-12-18 23:02:44 +01:00
broadcastInt ( " brightness " , brightness ) ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
void setBrightness ( uint8_t value )
2016-03-10 14:57:02 +01:00
{
if ( value > 255 )
value = 255 ;
else if ( value < 0 ) value = 0 ;
brightness = value ;
FastLED . setBrightness ( brightness ) ;
EEPROM . write ( 0 , brightness ) ;
EEPROM . commit ( ) ;
2016-12-18 23:02:44 +01:00
broadcastInt ( " brightness " , brightness ) ;
}
void strandTest ( )
{
static uint8_t i = 0 ;
EVERY_N_SECONDS ( 1 )
{
i + + ;
if ( i > = NUM_LEDS )
i = 0 ;
}
fill_solid ( leds , NUM_LEDS , CRGB : : Black ) ;
leds [ i ] = solidColor ;
2016-03-10 14:57:02 +01:00
}
void showSolidColor ( )
{
2019-01-13 16:45:50 +01:00
if ( allLeafs = = 0 & & selectedLeaf > 0 & & selectedLeaf < = LEAFCOUNT ) fill_solid ( leds + PIXELS_PER_LEAF * ( selectedLeaf - 1 ) , PIXELS_PER_LEAF , solidColor ) ;
else fill_solid ( leds , NUM_LEDS , solidColor ) ;
2016-03-10 14:57:02 +01:00
}
2016-12-18 23:02:44 +01:00
// Patterns from FastLED example DemoReel100: https://github.com/FastLED/FastLED/blob/master/examples/DemoReel100/DemoReel100.ino
2020-02-01 09:39:15 +01:00
void rainbow_strobe ( )
{
if ( autoplay = = 1 ) adjustPattern ( true ) ;
static bool p = false ;
static long lm = 0 ;
if ( millis ( ) - lm > ( 128 - ( speed / 2 ) ) )
{
if ( p ) fill_solid ( leds , NUM_LEDS , CRGB ( 0 , 0 , 0 ) ) ;
else fill_solid ( leds , NUM_LEDS , CHSV ( gHue , 255 , 255 ) ) ;
lm = millis ( ) ;
p = ! p ;
}
}
void strobe ( )
{
if ( autoplay = = 1 ) adjustPattern ( true ) ;
static bool p = false ;
static long lm = 0 ;
if ( millis ( ) - lm > ( 128 - ( speed / 2 ) ) )
{
if ( p ) fill_solid ( leds , NUM_LEDS , CRGB ( 0 , 0 , 0 ) ) ;
else fill_solid ( leds , NUM_LEDS , solidColor ) ;
lm = millis ( ) ;
p = ! p ;
}
}
2016-03-10 14:57:02 +01:00
void rainbow ( )
{
// FastLED's built-in rainbow generator
2019-01-13 16:45:50 +01:00
for ( int i = 0 ; i < LEAFCOUNT ; i + + )
{
uint8_t myHue = ( gHue + i * ( 255 / LEAFCOUNT ) ) ;
gHue = gHue > 255 ? gHue - 255 : gHue ;
//Serial.printf("I:%d \tH:%d\n", i*PIXELS_PER_LEAF, myHue);
fill_solid ( leds + i * PIXELS_PER_LEAF , PIXELS_PER_LEAF , CHSV ( myHue , 255 , 255 ) ) ;
}
2016-03-10 14:57:02 +01:00
}
void rainbowWithGlitter ( )
{
// built-in FastLED rainbow, plus some random sparkly glitter
rainbow ( ) ;
addGlitter ( 80 ) ;
}
2016-12-18 23:02:44 +01:00
void rainbowSolid ( )
2016-03-10 14:57:02 +01:00
{
2016-12-18 23:02:44 +01:00
fill_solid ( leds , NUM_LEDS , CHSV ( gHue , 255 , 255 ) ) ;
2016-03-10 14:57:02 +01:00
}
void confetti ( )
{
// random colored speckles that blink in and fade smoothly
2019-01-13 16:45:50 +01:00
fadeToBlackBy ( leds , NUM_LEDS , 3 ) ;
int pos = random16 ( LEAFCOUNT * 3 ) ;
2017-02-18 20:48:33 +01:00
// leds[pos] += CHSV( gHue + random8(64), 200, 255);
2019-01-13 16:45:50 +01:00
int val = gHue + random8 ( 64 ) ;
for ( int i = 0 ; i < ( PIXELS_PER_LEAF / 3 ) ; i + + )
{
leds [ i + pos * ( PIXELS_PER_LEAF / 3 ) ] + = ColorFromPalette ( palettes [ currentPaletteIndex ] , val ) ;
//Serial.printf("POS:%d\n", i + pos);
}
2016-03-10 14:57:02 +01:00
}
void sinelon ( )
{
// a colored dot sweeping back and forth, with fading trails
2019-01-13 16:45:50 +01:00
fadeToBlackBy ( leds , NUM_LEDS , 20 ) ;
2016-12-18 23:02:44 +01:00
int pos = beatsin16 ( speed , 0 , NUM_LEDS ) ;
static int prevpos = 0 ;
2017-02-18 20:48:33 +01:00
CRGB color = ColorFromPalette ( palettes [ currentPaletteIndex ] , gHue , 255 ) ;
2019-01-13 16:45:50 +01:00
if ( pos < prevpos ) {
fill_solid ( leds + pos , ( prevpos - pos ) + 1 , color ) ;
}
else {
fill_solid ( leds + prevpos , ( pos - prevpos ) + 1 , color ) ;
2016-12-18 23:02:44 +01:00
}
prevpos = pos ;
2016-03-10 14:57:02 +01:00
}
void bpm ( )
{
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
2019-01-13 16:45:50 +01:00
uint8_t beat = beatsin8 ( speed , 64 , 255 ) ;
CRGBPalette16 palette = palettes [ currentPaletteIndex ] ;
for ( int i = 0 ; i < LEAFCOUNT ; i + + ) {
2019-02-24 21:48:14 +01:00
for ( int i2 = 0 ; i2 < PIXELS_PER_LEAF ; i2 + + ) leds [ i * PIXELS_PER_LEAF + i2 ] = ColorFromPalette ( palette , gHue + ( i * 2 ) , beat - gHue + ( i * 10 ) ) ;
2019-01-13 16:45:50 +01:00
}
}
// BACKUP
/*
2019-02-24 21:48:14 +01:00
void bpm ( )
{
2019-01-13 16:45:50 +01:00
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint8_t beat = beatsin8 ( speed , 64 , 255 ) ;
2017-02-18 20:48:33 +01:00
CRGBPalette16 palette = palettes [ currentPaletteIndex ] ;
2019-01-13 16:45:50 +01:00
for ( int i = 0 ; i < NUM_LEDS ; i + + ) {
2017-02-18 20:48:33 +01:00
leds [ i ] = ColorFromPalette ( palette , gHue + ( i * 2 ) , beat - gHue + ( i * 10 ) ) ;
2016-03-10 14:57:02 +01:00
}
2019-02-24 21:48:14 +01:00
}
2019-01-13 16:45:50 +01:00
*/
2016-03-10 14:57:02 +01:00
void juggle ( )
{
2019-01-13 16:45:50 +01:00
static uint8_t numdots = 4 ; // Number of dots in use.
static uint8_t faderate = 2 ; // How long should the trails be. Very low value = longer trails.
static uint8_t hueinc = 255 / numdots - 1 ; // Incremental change in hue between each dot.
static uint8_t thishue = 0 ; // Starting hue.
static uint8_t curhue = 0 ; // The current hue
2016-12-18 23:02:44 +01:00
static uint8_t thissat = 255 ; // Saturation of the colour.
static uint8_t thisbright = 255 ; // How bright should the LED/display be.
2019-01-13 16:45:50 +01:00
static uint8_t basebeat = 5 ; // Higher = faster movement.
2016-12-18 23:02:44 +01:00
2019-01-13 16:45:50 +01:00
static uint8_t lastSecond = 99 ; // Static variable, means it's only defined once. This is our 'debounce' variable.
2016-12-18 23:02:44 +01:00
uint8_t secondHand = ( millis ( ) / 1000 ) % 30 ; // IMPORTANT!!! Change '30' to a different value to change duration of the loop.
if ( lastSecond ! = secondHand ) { // Debounce to make sure we're not repeating an assignment.
lastSecond = secondHand ;
switch ( secondHand ) {
2019-02-24 21:48:14 +01:00
case 0 : numdots = 1 ; basebeat = 20 ; hueinc = 16 ; faderate = 2 ; thishue = 0 ; break ; // You can change values here, one at a time , or altogether.
case 10 : numdots = 4 ; basebeat = 10 ; hueinc = 16 ; faderate = 8 ; thishue = 128 ; break ;
case 20 : numdots = 8 ; basebeat = 3 ; hueinc = 0 ; faderate = 8 ; thishue = random8 ( ) ; break ; // Only gets called once, and not continuously for the next several seconds. Therefore, no rainbows.
case 30 : break ;
2016-12-18 23:02:44 +01:00
}
}
// Several colored dots, weaving in and out of sync with each other
curhue = thishue ; // Reset the hue values.
fadeToBlackBy ( leds , NUM_LEDS , faderate ) ;
2019-01-13 16:45:50 +01:00
for ( int i = 0 ; i < numdots ; i + + ) {
2016-12-18 23:02:44 +01:00
//beat16 is a FastLED 3.1 function
leds [ beatsin16 ( basebeat + i + numdots , 0 , NUM_LEDS ) ] + = CHSV ( gHue + curhue , thissat , thisbright ) ;
curhue + = hueinc ;
2016-03-10 14:57:02 +01:00
}
}
2016-12-18 23:02:44 +01:00
void fire ( )
{
heatMap ( HeatColors_p , true ) ;
}
void water ( )
2017-02-18 20:48:33 +01:00
{
2016-12-18 23:02:44 +01:00
heatMap ( IceColors_p , false ) ;
2017-02-18 20:48:33 +01:00
}
2016-12-18 23:02:44 +01:00
2019-01-13 16:45:50 +01:00
// Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
// This function draws rainbows with an ever-changing,
// widely-varying set of parameters.
void pride ( )
{
static uint16_t sPseudotime = 0 ;
static uint16_t sLastMillis = 0 ;
static uint16_t sHue16 = 0 ;
uint8_t sat8 = beatsin88 ( 87 , 220 , 250 ) ;
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 1 , 3000 ) ;
uint16_t ms = millis ( ) ;
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms ;
sPseudotime + = deltams * msmultiplier ;
sHue16 + = deltams * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
for ( uint16_t i = 0 ; i < ( LEAFCOUNT * 3 ) ; i + + ) {
hue16 + = hueinc16 ;
uint8_t hue8 = hue16 / 256 ;
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
CRGB newcolor = CHSV ( hue8 , sat8 , bri8 ) ;
uint16_t pixelnumber = i ;
pixelnumber = ( ( LEAFCOUNT * 3 ) - 1 ) - pixelnumber ;
for ( int i2 = 0 ; i2 < ( PIXELS_PER_LEAF / 3 ) ; i2 + + )
{
2019-02-24 21:48:14 +01:00
nblend ( leds [ pixelnumber * ( PIXELS_PER_LEAF / 3 ) + i2 ] , newcolor , 64 ) ;
2019-01-13 16:45:50 +01:00
}
}
}
//#############BACKUP########################
/*
2019-02-24 21:48:14 +01:00
// Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
// This function draws rainbows with an ever-changing,
// widely-varying set of parameters.
void pride ( )
{
2016-03-10 14:57:02 +01:00
static uint16_t sPseudotime = 0 ;
static uint16_t sLastMillis = 0 ;
static uint16_t sHue16 = 0 ;
uint8_t sat8 = beatsin88 ( 87 , 220 , 250 ) ;
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 1 , 3000 ) ;
uint16_t ms = millis ( ) ;
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms ;
sPseudotime + = deltams * msmultiplier ;
sHue16 + = deltams * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
for ( uint16_t i = 0 ; i < NUM_LEDS ; i + + ) {
2019-01-13 16:45:50 +01:00
hue16 + = hueinc16 ;
uint8_t hue8 = hue16 / 256 ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
CRGB newcolor = CHSV ( hue8 , sat8 , bri8 ) ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
uint16_t pixelnumber = i ;
pixelnumber = ( NUM_LEDS - 1 ) - pixelnumber ;
2016-12-18 23:02:44 +01:00
2019-01-13 16:45:50 +01:00
nblend ( leds [ pixelnumber ] , newcolor , 64 ) ;
2016-12-18 23:02:44 +01:00
}
2019-02-24 21:48:14 +01:00
}
2016-12-18 23:02:44 +01:00
2019-01-13 16:45:50 +01:00
*/
2016-12-18 23:02:44 +01:00
void radialPaletteShift ( )
{
2018-10-06 20:09:10 +02:00
for ( uint16_t i = 0 ; i < NUM_LEDS ; i + + ) {
2016-12-18 23:02:44 +01:00
// leds[i] = ColorFromPalette( gCurrentPalette, gHue + sin8(i*16), brightness);
leds [ i ] = ColorFromPalette ( gCurrentPalette , i + gHue , 255 , LINEARBLEND ) ;
2016-03-10 14:57:02 +01:00
}
}
2016-12-18 23:02:44 +01:00
// based on FastLED example Fire2012WithPalette: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino
void heatMap ( CRGBPalette16 palette , bool up )
{
fill_solid ( leds , NUM_LEDS , CRGB : : Black ) ;
// Add entropy to random number generator; we use a lot of it.
random16_add_entropy ( random ( 256 ) ) ;
// Array of temperature readings at each simulation cell
2018-11-08 01:03:12 +01:00
static byte heat [ NUM_LEDS ] ;
2016-12-18 23:02:44 +01:00
byte colorindex ;
// Step 1. Cool down every cell a little
2019-01-13 16:45:50 +01:00
for ( uint16_t i = 0 ; i < NUM_LEDS ; i + + ) {
heat [ i ] = qsub8 ( heat [ i ] , random8 ( 0 , ( ( cooling * 10 ) / NUM_LEDS ) + 2 ) ) ;
2016-12-18 23:02:44 +01:00
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
2019-01-13 16:45:50 +01:00
for ( uint16_t k = NUM_LEDS - 1 ; k > = 2 ; k - - ) {
heat [ k ] = ( heat [ k - 1 ] + heat [ k - 2 ] + heat [ k - 2 ] ) / 3 ;
2016-12-18 23:02:44 +01:00
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
2019-01-13 16:45:50 +01:00
if ( random8 ( ) < sparking ) {
2016-12-18 23:02:44 +01:00
int y = random8 ( 7 ) ;
2019-01-13 16:45:50 +01:00
heat [ y ] = qadd8 ( heat [ y ] , random8 ( 160 , 255 ) ) ;
2016-12-18 23:02:44 +01:00
}
// Step 4. Map from heat cells to LED colors
2019-01-13 16:45:50 +01:00
for ( uint16_t j = 0 ; j < NUM_LEDS ; j + + ) {
2016-12-18 23:02:44 +01:00
// Scale the heat value from 0-255 down to 0-240
// for best results with color palettes.
colorindex = scale8 ( heat [ j ] , 190 ) ;
CRGB color = ColorFromPalette ( palette , colorindex ) ;
if ( up ) {
leds [ j ] = color ;
}
else {
leds [ ( NUM_LEDS - 1 ) - j ] = color ;
}
}
}
2019-01-13 16:45:50 +01:00
void addGlitter ( uint8_t chanceOfGlitter )
2016-12-18 23:02:44 +01:00
{
2019-01-13 16:45:50 +01:00
if ( random8 ( ) < chanceOfGlitter ) {
leds [ random16 ( NUM_LEDS ) ] + = CRGB : : White ;
2016-12-18 23:02:44 +01:00
}
}
///////////////////////////////////////////////////////////////////////
// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are. The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes [ ] ;
extern const uint8_t gGradientPaletteCount ;
2019-01-13 16:45:50 +01:00
uint8_t beatsaw8 ( accum88 beats_per_minute , uint8_t lowest = 0 , uint8_t highest = 255 ,
2019-02-24 21:48:14 +01:00
uint32_t timebase = 0 , uint8_t phase_offset = 0 )
2016-12-18 23:02:44 +01:00
{
2019-01-13 16:45:50 +01:00
uint8_t beat = beat8 ( beats_per_minute , timebase ) ;
2016-12-18 23:02:44 +01:00
uint8_t beatsaw = beat + phase_offset ;
uint8_t rangewidth = highest - lowest ;
2019-01-13 16:45:50 +01:00
uint8_t scaledbeat = scale8 ( beatsaw , rangewidth ) ;
2016-12-18 23:02:44 +01:00
uint8_t result = lowest + scaledbeat ;
return result ;
}
void colorWaves ( )
{
2019-01-13 16:45:50 +01:00
colorwaves ( leds , LEAFCOUNT * 3 , gCurrentPalette ) ;
2016-12-18 23:02:44 +01:00
}
2016-03-10 14:57:02 +01:00
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
2019-01-13 16:45:50 +01:00
void colorwaves ( CRGB * ledarray , uint16_t numleds , CRGBPalette16 & palette )
2016-03-10 14:57:02 +01:00
{
static uint16_t sPseudotime = 0 ;
static uint16_t sLastMillis = 0 ;
static uint16_t sHue16 = 0 ;
// uint8_t sat8 = beatsin88( 87, 220, 250);
2019-01-13 16:45:50 +01:00
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
2016-03-10 14:57:02 +01:00
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 300 , 1500 ) ;
uint16_t ms = millis ( ) ;
2019-01-13 16:45:50 +01:00
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms ;
2016-03-10 14:57:02 +01:00
sPseudotime + = deltams * msmultiplier ;
2019-01-13 16:45:50 +01:00
sHue16 + = deltams * beatsin88 ( 400 , 5 , 9 ) ;
2016-03-10 14:57:02 +01:00
uint16_t brightnesstheta16 = sPseudotime ;
2019-01-13 16:45:50 +01:00
for ( uint16_t i = 0 ; i < numleds ; i + + ) {
2016-03-10 14:57:02 +01:00
hue16 + = hueinc16 ;
uint8_t hue8 = hue16 / 256 ;
uint16_t h16_128 = hue16 > > 7 ;
2019-01-13 16:45:50 +01:00
if ( h16_128 & 0x100 ) {
2016-03-10 14:57:02 +01:00
hue8 = 255 - ( h16_128 > > 1 ) ;
2019-01-13 16:45:50 +01:00
}
else {
2016-03-10 14:57:02 +01:00
hue8 = h16_128 > > 1 ;
}
2019-01-13 16:45:50 +01:00
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
2016-03-10 14:57:02 +01:00
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
uint8_t index = hue8 ;
//index = triwave8( index);
2019-01-13 16:45:50 +01:00
index = scale8 ( index , 240 ) ;
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
CRGB newcolor = ColorFromPalette ( palette , index , bri8 ) ;
2016-12-18 23:02:44 +01:00
uint16_t pixelnumber = i ;
2019-01-13 16:45:50 +01:00
//pixelnumber = (numleds - 1) - pixelnumber;
//nblend(ledarray[pixelnumber], newcolor, 128);
2016-03-10 14:57:02 +01:00
2019-01-13 16:45:50 +01:00
pixelnumber = ( ( LEAFCOUNT * 3 ) - 1 ) - pixelnumber ;
for ( int i2 = 0 ; i2 < ( PIXELS_PER_LEAF / 3 ) ; i2 + + )
{
2019-02-24 21:48:14 +01:00
nblend ( leds [ pixelnumber * ( PIXELS_PER_LEAF / 3 ) + i2 ] , newcolor , 128 ) ;
2019-01-13 16:45:50 +01:00
}
2016-03-10 14:57:02 +01:00
}
}
// Alternate rendering function just scrolls the current palette
// across the defined LED strip.
2019-01-13 16:45:50 +01:00
void palettetest ( CRGB * ledarray , uint16_t numleds , const CRGBPalette16 & gCurrentPalette )
2016-03-10 14:57:02 +01:00
{
static uint8_t startindex = 0 ;
startindex - - ;
2019-01-13 16:45:50 +01:00
fill_palette ( ledarray , numleds , startindex , ( 256 / NUM_LEDS ) + 1 , gCurrentPalette , 255 , LINEARBLEND ) ;
2016-03-10 14:57:02 +01:00
}
2019-02-24 21:48:14 +01:00
/*
Function : ExtractValues
Used to extract a given amount of values from the message with a start index
Parameters :
- startindex : position in the string where to start
- valuecount : amount of values to capture
*/
void ExtractValues ( char receivedChars [ ] , int startindex , int valuecount )
{
int pos = startindex ;
for ( int c = 0 ; c < valuecount ; c + + )
{
int i = 0 ;
while ( receivedChars [ pos ] ! = ' ; ' & & receivedChars [ pos ] ! = ' \0 ' ) {
vals [ c ] [ i ] = receivedChars [ pos ] ;
pos + + ;
i + + ;
}
vals [ c ] [ i ] = ' \0 ' ;
pos + + ;
}
# ifdef DEBUG_SERIAL
for ( int p = 0 ; p < valuecount ; p + + )
{
Serial . print ( " Extracting: " ) ; Serial . println ( vals [ p ] ) ;
}
# endif // DEBUG_SERIAL
}
void cycle ( CRGB endclr , CRGB midclr , uint8_t start ) {
fill_gradient_RGB ( leds , start , endclr , PIXELS_PER_LEAF / 2 , midclr ) ;
fill_gradient_RGB ( leds , PIXELS_PER_LEAF / 2 + 1 , midclr , PIXELS_PER_LEAF , endclr ) ;
}
// Set Custom Pattern for the node red part
void SetCustomPattern ( )
{
uint8_t cnt = 0 ;
uint8_t isflow = 0 ;
ExtractValues ( cpattern , 0 , 2 ) ;
cnt = atoi ( vals [ 0 ] ) ;
isflow = atoi ( vals [ 1 ] ) ;
ExtractValues ( cpattern , 0 , 2 + 5 * cnt ) ;
if ( isflow = = 0 )
{
for ( uint8_t i = 0 ; i < cnt ; i + + )
{
int8_t cmode = atoi ( vals [ 2 + i * 5 ] ) ;
uint8_t phase = atoi ( vals [ 2 + i * 5 + 1 ] ) ;
int mul = breathe ;
if ( breathe_dir = = 1 )
{
if ( ( mul + phase ) > 255 ) mul = 255 + ( 255 - mul - phase ) ;
else mul + = phase ;
}
else
{
if ( ( mul - phase ) < 0 ) mul = - mul + phase ;
else mul - = phase ;
}
if ( cmode = = 0 ) mul = 255 ;
double fac = ( mul * 100 ) / 255.00 ;
//if(cmode==1)Serial.printf("%d ", mul);
for ( uint8_t x = 0 ; x < PIXELS_PER_LEAF ; x + + )
{
//Serial.printf("Setting %d to %d, %d, %d\n", cnt*PIXELS_PER_LEAF+x,atoi(vals[2+i*5+2]), atoi(vals[2+i*5+3]), atoi(vals[2+i*5+4]));
leds [ i * PIXELS_PER_LEAF + x ] = CRGB ( ( atoi ( vals [ 2 + i * 5 + 2 ] ) * fac ) / 100.00 , ( atoi ( vals [ 2 + i * 5 + 3 ] ) * fac ) / 100.00 , ( atoi ( vals [ 2 + i * 5 + 4 ] ) * fac ) / 100.00 ) ;
}
}
}
else
{
for ( int i = 0 ; i < cnt ; i + + )
{
if ( i ! = ( cnt - 1 ) )
{
//uint8_t speed = beatsin8(6,0,255);
CRGB endclr = blend ( CRGB ( atoi ( vals [ 2 + i * 5 + 2 ] ) , atoi ( vals [ 2 + i * 5 + 3 ] ) , atoi ( vals [ 2 + i * 5 + 4 ] ) ) , CRGB ( atoi ( vals [ 2 + ( i + 1 ) * 5 + 2 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 3 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 4 ] ) ) , breathe ) ;
CRGB midclr = blend ( CRGB ( atoi ( vals [ 2 + ( i + 1 ) * 5 + 2 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 3 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 4 ] ) ) , CRGB ( atoi ( vals [ 2 + i * 5 + 2 ] ) , atoi ( vals [ 2 + i * 5 + 3 ] ) , atoi ( vals [ 2 + i * 5 + 4 ] ) ) , breathe ) ;
cycle ( endclr , midclr , i * PIXELS_PER_LEAF ) ;
}
else
{
//uint8_t speed = beatsin8(6,0,255);
CRGB endclr = blend ( CRGB ( atoi ( vals [ 2 + 2 ] ) , atoi ( vals [ 2 + 3 ] ) , atoi ( vals [ 2 + 4 ] ) ) , CRGB ( atoi ( vals [ 2 + ( i + 1 ) * 5 + 2 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 3 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 4 ] ) ) , breathe ) ;
CRGB midclr = blend ( CRGB ( atoi ( vals [ 2 + ( i + 1 ) * 5 + 2 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 3 ] ) , atoi ( vals [ 2 + ( i + 1 ) * 5 + 4 ] ) ) , CRGB ( atoi ( vals [ 2 + 2 ] ) , atoi ( vals [ 2 + 3 ] ) , atoi ( vals [ 2 + 4 ] ) ) , breathe ) ;
cycle ( endclr , midclr , i * PIXELS_PER_LEAF ) ;
}
}
}
//Serial.println("");
}
2020-02-01 09:39:15 +01:00
// #################### Sound Reactive and Alexa below
void soundReactive ( )
{
static int minlevel = 0 ;
static int decay = 60 ;
static double lastlevel = 2 ;
static double level = 0 ;
# define arrsize 3
static double measure8avg [ arrsize ] = { 0 , 0 , 0 } ;
static int iter = 0 ;
# if SENSOR_TYPE == 0
if ( digitalRead ( SOUND_SENSOR_PIN ) > 0 ) level + + ;
else level - - ;
if ( level < minlevel ) level = minlevel ;
if ( level > LEDS_PER_LINE ) level = LEDS_PER_LINE ;
fill_solid ( leds , level , CHSV ( gHue , 255 , 255 ) ) ;
fadeToBlackBy ( leds + level , LEDS_PER_LINE - level , decay ) ;
# endif
# if SENSOR_TYPE > 0
# if SENSOR_TYPE == 2
int measure = 0 ;
for ( int it = 0 ; it < 5 ; it + + )
{
int m = analogRead ( SOUND_SENSOR_PIN ) ;
Serial . println ( m ) ;
if ( m < 450 & & m > 350 ) m = 0 ;
else if ( m < 350 ) m = ( 400 - m ) * 2 ;
if ( m > 400 ) m - = 400 ;
measure + = m ;
}
measure / = 5 ;
# endif
# if SENSOR_TYPE == 1
int measure = 0 ;
for ( int it = 0 ; it < 5 ; it + + )
{
int m = analogRead ( SOUND_SENSOR_PIN ) ;
m - = 800 ;
m * = - 1 ;
if ( m < 100 ) m = 0 ;
measure + = m ;
}
measure / = 5 ;
measure / = 2 ; // cut the volts in half
# endif
//Serial.println(measure);
iter + + ;
if ( iter > arrsize ) iter = 0 ;
measure8avg [ iter ] = measure ;
double avg = 0 ;
for ( int x = 0 ; x < arrsize ; x + + )
{
avg + = measure8avg [ x ] ;
}
avg / = arrsize ;
avg = measure ;
int mlevel = map ( avg , 30 , 300 , 1 , NUM_LEDS ) ;
if ( mlevel < 1 ) mlevel = 1 ;
//if (lastlevel > mlevel) level = lastlevel - 0.8;
//else if (lastlevel < mlevel) level = lastlevel+1;
level = mlevel ;
if ( level < minlevel ) level = minlevel ;
if ( level > NUM_LEDS ) level = NUM_LEDS ;
fill_solid ( leds , level , CHSV ( gHue , 255 , 255 ) ) ;
fadeToBlackBy ( leds + ( int ) level , NUM_LEDS - ( int ) level , decay ) ;
lastlevel = level ;
//Serial.print(mlevel); Serial.print(" "); Serial.println(level);
//Serial.printf("%d, %d\n", mlevel, level);
# endif
}
//############################## ALEXA Device Events ##############################
# ifdef ENABLE_ALEXA_SUPPORT
void mainAlexaEvent ( EspalexaDevice * d ) {
if ( d = = nullptr ) return ;
Serial . print ( " Alexa update: rgb: " ) ; Serial . print ( d - > getR ( ) + d - > getG ( ) + d - > getB ( ) ) ; Serial . print ( " , b: " ) ; Serial . println ( d - > getValue ( ) ) ;
if ( d - > getValue ( ) = = 0 ) setPower ( 0 ) ; else {
setPower ( 1 ) ;
setBrightness ( d - > getValue ( ) ) ;
}
static int lr ;
static int lg ;
static int lb ;
if ( ( lr ! = NULL & & lr ! = d - > getR ( ) & & lg ! = d - > getG ( ) & & lb ! = d - > getB ( ) ) | | currentPatternIndex = = patternCount - 1 )
{
setSolidColor ( d - > getR ( ) , d - > getG ( ) , d - > getB ( ) ) ;
setPattern ( patternCount - 1 ) ;
}
lr = d - > getR ( ) ;
lg = d - > getG ( ) ;
lb = d - > getB ( ) ;
}
# ifdef AddStrobeDevice
void AlexaStrobeEvent ( EspalexaDevice * d ) {
if ( d = = nullptr ) return ;
Serial . print ( " Alexa Strobe update: rgb: " ) ; Serial . print ( d - > getR ( ) + d - > getG ( ) + d - > getB ( ) ) ; Serial . print ( " , b: " ) ; Serial . println ( d - > getValue ( ) ) ;
if ( d - > getValue ( ) = = 0 ) setPattern ( patternCount - 1 ) ; else {
if ( d - > getValue ( ) = = 255 )
{
setBrightness ( 255 ) ;
setPattern ( 13 ) ;
}
else speed = d - > getValue ( ) ;
d - > setValue ( speed ) ;
}
static int lr ;
static int lg ;
static int lb ;
if ( ( lr ! = NULL & & lr ! = d - > getR ( ) & & lg ! = d - > getG ( ) & & lb ! = d - > getB ( ) ) | | currentPatternIndex = = patternCount - 1 )
{
setSolidColor ( d - > getR ( ) , d - > getG ( ) , d - > getB ( ) ) ;
setPattern ( 12 ) ;
}
lr = d - > getR ( ) ;
lg = d - > getG ( ) ;
lb = d - > getB ( ) ;
}
# endif
# ifdef AddAutoplayDevice
void AlexaAutoplayEvent ( EspalexaDevice * d ) {
if ( d = = nullptr ) return ;
Serial . print ( " Alexa Autoplay update: state: " ) ; Serial . println ( d - > getPercent ( ) ) ;
if ( d - > getValue ( ) > 0 )
{
setAutoplay ( 1 ) ;
setAutoplayDuration ( d - > getPercent ( ) ) ;
}
else setAutoplay ( 0 ) ;
}
# endif
# ifdef AddSpecificPatternDevice
void AlexaSpecificEvent ( EspalexaDevice * d ) {
if ( d = = nullptr ) return ;
Serial . print ( " Alexa Specific Pattern update: state: " ) ; Serial . println ( d - > getValue ( ) ) ;
if ( d - > getValue ( ) ! = 0 ) setPattern ( SpecificPattern ) ;
else setPattern ( patternCount - 1 ) ;
}
# endif
# endif