|
|
#include <Arduino.h>
// LED
// TODO : essayer, devrait limiter le flikering
//#define FASTLED_ALLOW_INTERRUPTS 0
#define FASTLED_ESP8266_NODEMCU_PIN_ORDER
#include <FastLED.h>
// WIFI
#include <ESP8266WiFi.h>
// MQTT
#include <PubSubClient.h>
// OTA
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
// RemoteDebug
#include <RemoteDebug.h>
#include "mqttfastledmenu.h"
// LED
// En déplaçant ces vars dans le .h + init dans le setup, cylon crash au moment du premier retour ?!
float brightness = LED_BRIGHTNESS_DEFAULT;int color = LED_COLOR_DEFAULT;int speed = LED_SPEED_DEFAULT;CRGB leds[LED_NUM];String ledEffect = LED_EFFECT_ERROR;boolean ledState = false;
// WIFI
WiFiClient espClient;
// MQTT
char message_buff[100];PubSubClient client(espClient);
void setup(){ Serial.begin(SERIAL_SPEED); Serial.println("\nresetting");
// WIFI
setupWifi();
// OTA
setupOTA();
// RemoteDebug
Debug.begin("chamber");
// LED
/*
brightness = LED_BRIGHTNESS_DEFAULT; color = LED_COLOR_DEFAULT; speed = LED_SPEED_DEFAULT; ledEffect = LED_EFFECT_ERROR; ledState = false; */
LEDS.addLeds<LED_CHIPSET,LED_PIN, LED_COLOR_ORDER>(leds, LED_NUM).setCorrection(TypicalSMD5050); ledBlackAll(); FastLED.setBrightness(brightness);
//////////////////////////////// ColorPalette ///////////////////////////////
currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; //////////////////////////////// ColorPalette ///////////////////////////////
// MQTT
client.setServer(MQTT_SERVER, MQTT_PORT); client.setCallback(callbackMQTT); testConnectMQTT();
Debug.println("Ready");
/* MQTT
* Il est important de faire un loop avant toute chose, * afin de récupérer les valeurs provenant du broker mqtt * et pas démarrer avec de vieilles infos. * Il faut un certains nombres de tentative pour tout récuperer. */ for (short int i = 0; i < 10; i++) { delay(200); client.loop(); }
Debug.println("End of setup");}
// OTA
void setupOTA(){ ArduinoOTA.setHostname("mqttfastledmenu"); // on donne une petit nom a notre module
ArduinoOTA.setPassword(OTA_PASSWORD); ArduinoOTA.onStart([]() { Debug.println("OTA Starting"); Serial.println("OTA Starting"); }); ArduinoOTA.onEnd([]() { Debug.println("\nOTA End"); Serial.println("\nOTA End"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Debug.printf("OTA Progress: %u%%\r", (progress / (total / 100))); Serial.printf("OTA Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("OTA Error[%u]: ", error); Debug.printf("OTA Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); Debug.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); Debug.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); Debug.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); Debug.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); Debug.println("End Failed"); } }); ArduinoOTA.begin();}
// WIFI
void setupWifi(){ Serial.print("Connexion a "); Serial.print(WIFI_SSID); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" OK"); Serial.print("IP : "); Serial.println(WiFi.localIP());}
// MQTT
void testConnectMQTT(){ while (!client.connected()) { Debug.print("Connexion au serveur MQTT... "); // TODO : changer ça pour un truc specifique sinon provoque des erreurs mqtt
if (client.connect(MQTT_CLIENT, MQTT_USER, MQTT_PASS)) { Debug.print("OK\nSend Current State"); mqttSendState(); mqttSendSpeedState(); mqttSendBrightnessState(); mqttSendEffectState(); mqttSendColorState();
Debug.print("OK\nSubscribe"); client.subscribe(MQTT_LED_COMMAND); client.subscribe(MQTT_LED_EFFECT_COMMAND); client.subscribe(MQTT_LED_BRIGHTNESS_COMMAND); client.subscribe(MQTT_LED_SPEED_COMMAND); client.subscribe(MQTT_LED_COLOR_COMMAND);
Debug.println(" OK"); } else { Debug.print("KO, erreur : "); Debug.print(client.state()); Debug.println(", on attend 5 secondes avant de recommencer"); delay(5000); } }}
// Déclenche les actions à la réception d'un message
void callbackMQTT(char* topic, byte* payload, unsigned int length){ String stopic = String(topic);
unsigned int i = 0; for(i = 0; i < length; i++) { message_buff[i] = payload[i]; } message_buff[i] = '\0'; String msgString = String(message_buff);
Debug.print("Received [" + stopic + "] : "); Debug.println(msgString);
if (stopic == MQTT_LED_COMMAND) { if (msgString == "ON") { ledState = true; } else { ledState = false; ledBlackAll(); } mqttSendState(); } else if (stopic == MQTT_LED_EFFECT_COMMAND) { // Si on ne repasse pas tout à noir, cela peut faire des effets surprenants
ledBlackAll(); ledEffect = msgString; mqttSendEffectState(); } else if (stopic == MQTT_LED_BRIGHTNESS_COMMAND) { brightness = msgString.toInt(); FastLED.setBrightness(brightness); mqttSendBrightnessState(); } else if (stopic == MQTT_LED_COLOR_COMMAND) { // Sample : 134,168,255
int red = msgString.substring(0, msgString.indexOf(',')).toInt(); int green = msgString.substring(msgString.indexOf(',') + 1, msgString.lastIndexOf(',')).toInt(); int blue = msgString.substring(msgString.lastIndexOf(',') + 1).toInt();
color=((red <<16)|(green <<8)|blue); mqttSendColorState(); } else if (stopic == MQTT_LED_SPEED_COMMAND) { speed = msgString.toInt(); mqttSendSpeedState(); }}
void mqttSendState(){ client.publish(MQTT_LED_STATE, (ledState) ? "ON": "OFF", true);}
void mqttSendEffectState(){ char buff[ledEffect.length() + 1]; ledEffect.toCharArray(buff, ledEffect.length() + 1); client.publish(MQTT_LED_EFFECT_STATE, buff, true);}
void mqttSendBrightnessState(){ char buff[4]; itoa(brightness, buff, 10); client.publish(MQTT_LED_BRIGHTNESS_STATE, buff, true);}
void mqttSendSpeedState(){ char buff[4]; itoa(speed, buff, 10); client.publish(MQTT_LED_SPEED_STATE, buff, true);}
void mqttSendColorState(){ int red = color>>16 & 0xFF; int green = color>>8 & 0xFF; int blue = color & 0xFF; char buff[12];
sprintf(buff, "%i,%i,%i", red, green, blue); client.publish(MQTT_LED_COLOR_STATE, buff, true);}
// LED
/**
* Coupe tout le strip de led.*/void ledBlackAll(){ FastLED.clear(); FastLED.show();}
/**
* Effet Cylon : défilement d'une simple led sur le strip aller/retour.* Pour faire plus sympas on ajoute une lueur autour, avec une lumière atténué.*/void ledCylon(){ for (int i = 0; i < LED_NUM; i++) { client.loop();
if (ledEffect != LED_EFFECT_CYLON) { return; }
if ((i - 3) >= 0) { leds[i - 3] = CRGB::Black; } if ((i - 2) >= 0) { /*
* Se lit 128/256 d'intensité lumineuse actuelle * https://github.com/FastLED/FastLED/wiki/Pixel-reference#dimming-and-brightening-colors
*/ leds[i - 2] = color; leds[i - 2].fadeLightBy(220); } if ((i - 1) >= 0) { leds[i - 1] = color; leds[i - 1].fadeLightBy(200); }
leds[i] = color;
if ((i + 1) <= LED_NUM) { leds[i + 1] = color; // Je suis volontairement un peu moins puissant sur l'avant
// pour donner un effet de trainée sur l'arrière
leds[i + 1].fadeLightBy(249); }
FastLED.delay(1000 / speed); } // Il faut nettoyer certaines cases avant la prochaine loop
if ((LED_NUM - 2) >= 0) { leds[LED_NUM - 2] = color; leds[LED_NUM - 2].fadeLightBy(220); } if ((LED_NUM - 1) >= 0 ) { leds[LED_NUM - 1] = CRGB::Black; } FastLED.show();
// led[0] et led[255] sont gérées par la loop précédante
for (int i = LED_NUM - 1; i >= 0; i--) { client.loop(); if (ledEffect != LED_EFFECT_CYLON) { return; } if ((i - 1) >= 0) { leds[i - 1] = color; leds[i - 1].fadeLightBy(249); }
leds[i] = color;
if ((i + 1) <= LED_NUM) { leds[i + 1] = color; leds[i + 1].fadeLightBy(200); }
if ((i + 2) <= LED_NUM) { leds[i + 2] = color; leds[i + 2].fadeLightBy(220); }
if ((i + 3) <= LED_NUM) { leds[i + 3] = CRGB::Black; } FastLED.delay(1000 / speed); } // Il faut nettoyer certaines cases avant la prochaine loop
if (1 <= LED_NUM) { leds[1] = color; leds[1].fadeLightBy(220); } if (2 <= LED_NUM) { leds[2] = CRGB::Black; } FastLED.show();}
/**
* Utilise pour indiquer une erreur sur la reception de l'effet. */void ledError(){ for (int i = 0; i < LED_NUM; i++) { if ((i % 2) == 0) { leds[i] = CRGB::Black; } else { leds[i] = CRGB::Red; } }
FastLED.delay(1000 / speed);}
/**
* Affiche une couleur de manière uniforme sur le strip. * Pour éviter un éclairage basique, on applique un breath qui permet * de faire respirer la couleur (brightness). */void ledBreathing(){
// Source : http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
// Voic la version avec la gestion du speed, mais je ne suis pas convaincu
//float breath = (exp(sin(millis() / 2000.0 * map(speed, 0, 255, 50, 300)/100 * PI)) - 0.3678794) * 108.4;
float breath = (exp(sin(millis() / 4000.0 * PI)) - 0.3678794) * 108.4;
// J'ai essayé de mapper breath sur 3;brightness pour ne pas eteindre les leds,
// mais l'effet est plus saccadé
fill_solid(leds, LED_NUM, color); FastLED.setBrightness(breath); FastLED.show();}
///////////////////// FastLED-3.1.5/examples/ColorPalette /////////////////////
void ledColorPattern(){ ChangePalettePeriodically();
static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */
FillLEDsFromPaletteColors(startIndex);
FastLED.delay(1000 / speed);}
void FillLEDsFromPaletteColors(uint8_t colorIndex){ uint8_t brightness = 255;
for( int i = 0; i < LED_NUM; i++) { leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending ); colorIndex += 3; }}
// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly. All are shown here.
void ChangePalettePeriodically(){ uint8_t secondHand = (millis() / 1000) % 60; static uint8_t lastSecond = 99;
if( lastSecond != secondHand) { lastSecond = secondHand; /*
if (secondHand == 0) { currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; } if (secondHand == 10) { currentPalette = RainbowStripeColors_p; currentBlending = NOBLEND; } if (secondHand == 15) { currentPalette = RainbowStripeColors_p; currentBlending = LINEARBLEND; } if (secondHand == 20) { SetupPurpleAndGreenPalette(); currentBlending = LINEARBLEND; } if (secondHand == 25) { SetupTotallyRandomPalette(); currentBlending = LINEARBLEND; } if (secondHand == 30) { SetupBlackAndWhiteStripedPalette(); currentBlending = NOBLEND; } if (secondHand == 35) { SetupBlackAndWhiteStripedPalette(); currentBlending = LINEARBLEND; } if (secondHand == 40) { currentPalette = CloudColors_p; currentBlending = LINEARBLEND; } if (secondHand == 45) { currentPalette = PartyColors_p; currentBlending = LINEARBLEND; } if (secondHand == 50) { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; } if (secondHand == 55) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; } */ if (secondHand == 0) { SetupPurpleAndGreenPalette(); currentBlending = LINEARBLEND; } if (secondHand == 10) { SetupBlackAndWhiteStripedPalette(); currentBlending = LINEARBLEND; } if (secondHand == 30) { currentPalette = CloudColors_p; currentBlending = LINEARBLEND; } if (secondHand == 40) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; } }}
/*
// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette(){ for (int i = 0; i < 16; i++) { currentPalette[i] = CHSV(random8(), 255, random8()); }}*/
// This function sets up a palette of black and white stripes,
// using code. Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette(){ // 'black out' all 16 palette entries...
fill_solid(currentPalette, 16, CRGB::Black); // and set every fourth one to white.
currentPalette[0] = CRGB::White; currentPalette[4] = CRGB::White; currentPalette[8] = CRGB::White; currentPalette[12] = CRGB::White;}
// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette(){ CRGB purple = CHSV(HUE_PURPLE, 255, 255); CRGB green = CHSV(HUE_GREEN, 255, 255); CRGB black = CRGB::Black;
currentPalette = CRGBPalette16( green, green, black, black, purple, purple, black, black, green, green, black, black, purple, purple, black, black );}///////////////////// FastLED-3.1.5/examples/ColorPalette /////////////////////
/////////////////// FastLED-3.1.5/examples/ColorTemperature ///////////////////
void colorTemp(){ // draw a generic, no-name rainbow
static uint8_t starthue = 0; fill_rainbow(leds + 5, LED_NUM - 5, --starthue, 20);
// Choose which 'color temperature' profile to enable.
uint8_t secs = (millis() / 1000) % (DISPLAYTIME * 2); if (secs < DISPLAYTIME) { FastLED.setTemperature(TEMPERATURE_1 ); // first temperature
leds[0] = TEMPERATURE_1; // show indicator pixel
} else { FastLED.setTemperature(TEMPERATURE_2 ); // second temperature
leds[0] = TEMPERATURE_2; // show indicator pixel
}
// Black out the LEDs for a few secnds between color changes
// to let the eyes and brains adjust
if((secs % DISPLAYTIME) < BLACKTIME) { memset8(leds, 0, LED_NUM * sizeof(CRGB)); }
FastLED.show(); FastLED.delay(8);}/////////////////// FastLED-3.1.5/examples/ColorTemperature ///////////////////
//////////////////////// FastLED-3.1.5/examples/Fire202 ///////////////////////
void fire(){ // Array of temperature readings at each simulation cell
static byte heat[LED_NUM];
// Step 1. Cool down every cell a little
for (int i = 0; i < LED_NUM; i++) { heat[i] = qsub8(heat[i], random8(0, ((COOLING * 10) / LED_NUM) + 2)); }
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for (int k= LED_NUM - 1; k >= 2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; }
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if (random8() < SPARKING ) { int y = random8(7); heat[y] = qadd8(heat[y], random8(160,255)); }
// Step 4. Map from heat cells to LED colors
for (int j = 0; j < LED_NUM; j++) { CRGB color = HeatColor( heat[j]); int pixelnumber; if (gReverseDirection) { pixelnumber = (LED_NUM - 1) - j; } else { pixelnumber = j; } leds[pixelnumber] = color; }
FastLED.delay(1000 / speed);}//////////////////////// FastLED-3.1.5/examples/Fire202 ///////////////////////
void loop() { // OTA
ArduinoOTA.handle();
// RemoteDebug
Debug.handle();
// MQTT
testConnectMQTT(); client.loop();
// LED
if (!ledState) { FastLED.delay(1000); } else { if (ledEffect == LED_EFFECT_CYLON) { ledCylon(); } else if (ledEffect == LED_EFFECT_BREATHING) { ledBreathing(); } else if (ledEffect == LED_EFFECT_COLORPATTERN) { ledColorPattern(); } else if (ledEffect == LED_EFFECT_COLORTEMP) { colorTemp(); } else if (ledEffect == LED_EFFECT_FIRE) { fire(); } else { ledError(); } }}
|