Controlar Fita LED NeoPixel via Wi-Fi: Projeto ESP8266 com App Android
Componentes e Materiais
| Placa ElectroPeak ESP8266 Serial WIFI Witty Cloud Board | × | 1 |
| Fita LED Inteligente NeoPixels (60 LED/m) | × | 3 |
| Conversor de Nível Lógico ElectroPeak | × | 1 |
| Fios Jumper 21cm 40P Macho-Fêmea ElectroPeak | × | 1 |
| Tubo PVC 60cm tamanho 2" | × | 1 |
| Papel vegetal (tracing paper) | × | 1 |
| Cilindro de vidro | × | 1 |
| Fonte de alimentação 5V (pelo menos 9A) | × | 1 |
| Arduino Nano R3 | × | 1 |
Ferramentas e Máquinas Necessárias
- Pistola de cola quente (genérica)
- Ferro de soldar (genérico)
Aplicações e Serviços Online
- Arduino IDE
Sobre este Projeto
Pode ler este e outros tutoriais incríveis no site oficial da ElectroPeak
Crie um efeito de simulação de fogo com controle sem fio Wi-Fi. Uma app móvel (para smartphones Android) com uma interface bonita está pronta para instalar e brincar com a sua criação! Também usaremos Arduino e ESP8266 para controlar a chama. No final deste projeto vai aprender:
- Como funcionam os NeoPixels.
- Como programar o ESP8266 e controlar variáveis via Wi-Fi.
- Como criar um efeito de fogo legal com NeoPixels.
Introdução aos NeoPixels
LEDs individualmente endereçáveis, frequentemente chamados de NeoPixels, existem há algum tempo e provavelmente já os conhece, mas, se não, são como LEDs RGB normais, mas, como o nome sugere, a cor de cada um pode ser endereçada individualmente, permitindo padrões e animações infinitamente legais. Para WS2812b precisa apenas de 3 fios, 2 para alimentação e 1 para dados. Isso significa que precisa apenas de um pino livre do Arduino para controlar uma tonelada de LEDs!
Neste projeto, vamos usar estes LEDs inteligentes para criar um efeito de fogo. Para controlar os LEDs vamos usar a fantástica biblioteca FastLED. Vamos usar o sketch de exemplo Fire2012 da biblioteca escrito por Mark Kriegsman. Usamos 6 tiras de LEDs cada uma com 30 LEDs (um total de 180 LEDs), colamos estes LEDs num tubo PVC e colocamos num cilindro de vidro (estes cilindros são geralmente usados como vasos). Temos de difundir a luz dos LEDs para que pareçam contínuos, para isso usamos papel vegetal que deixa passar a luz e a difunde.

Construção
Primeiro, arranje um cilindro de vidro adequado. O nosso cilindro tem 60cm de comprimento e 12cm de diâmetro.
Se encontrar um cilindro de vidro fosco, óptimo, mas se for vidro transparente pode usar papel vegetal para cobrir a superfície do cilindro (superfície interna ou externa), o papel vegetal faz um bom trabalho difundindo a luz e produz bons resultados.
Depois de obter o cilindro de vidro, meça o seu comprimento interno e corte o tubo PVC para que caiba dentro do cilindro. O nosso cilindro tem 60cm de altura (excluindo a base, tem um comprimento interno de 59cm), então cortámos o tubo PVC para 59cm. Irá colar as tiras de LED neste tubo, um tubo com 4cm de diâmetro seria perfeito.
Em seguida, temos de cortar a nossa tira de LED em 6 partes iguais. Aqui usamos tira de densidade 60 LEDs/m (pode usar densidades maiores para melhores efeitos se quiser). Usamos seis comprimentos de 50cm, o que significa que precisamos de 3 metros. Espace os seis comprimentos igualmente à volta do tubo PVC e cole as tiras no tubo. Deverá ficar assim:





Para ligar as tiras de LED, pode soldar fios diretamente na tira de acordo com o desenho seguinte ou primeiro soldar headers de pinos nas tiras e depois usar fios de protoboard para as ligar.

Quando todas as conexões das tiras de LED estiverem prontas, tem de colocar o tubo dentro do cilindro. Para centrar o tubo dentro do cilindro, pode usar espuma para cortar um círculo que tenha diâmetro externo igual ao diâmetro interno do cilindro de vidro e diâmetro interno igual ao diâmetro externo do tubo PVC. Prepare dois destes para cada lado do tubo. Prenda estas peças nas extremidades e coloque suavemente o tubo dentro do cilindro.
Código
Usamos Arduino IDE para programar e carregar para o ESP8266. Tem de usar uma placa que tenha um ESP8266 com 3MB de SPIFFS se quiser carregar os ficheiros do software de controlo no SPIFFS. SPIFFS significa "Serial Peripheral Interface Flash File System", pode carregar os ficheiros do controlador para esta memória para servir os ficheiros a partir dessa localização. Ao fazer isso, pode abrir o seu browser (no telemóvel ou portátil) e ir ao endereço do seu ESP (o padrão é 192.168.4.1) e obterá a interface de controlo no seu browser sem ter de instalar a app, se tiver um iPhone ou iPad esta é a sua única escolha.
Carregue o seguinte sketch na sua placa ESP. Precisamos da biblioteca FastLED, então primeiro adicione-a ao seu Arduino IDE se ainda não o fez (Pode baixá-la aqui). O código de simulação de fogo é o sketch fire2012 de Mark Kriegsman que pode encontrar nos exemplos. Esse exemplo é para uma tira de LED, mas aqui modificámos o código para usar um número variável de tiras. Quanto mais tiras/LEDs, maior será o efeito.
A lógica da simulação de fogo está claramente descrita no ficheiro de exemplo. Se quiser saber como funciona, leia o código fonte do exemplo.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "FastLED.h"
#include "EEPROM.h"
#include "FS.h" //required for SPIFFS
#define DATA_PIN 5
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
#define NUM_LEDS 30
#define NUM_STRIPS 6
#define CHIPSET WS2812B
//endereços para guardar dados na EEPROM para preservar o estado da simulação de fogo
#define cs0Adr 0
#define cs1Adr 3
#define cs2Adr 6
#define cs3Adr 9
#define BriAdr 15
#define FpsAdr 16
#define SparkingAdr 17
#define CoolingAdr 18
#define EEPROMCheckAdr 20
//se este valor for 250 assumimos que já guardámos na EEPROM e carregamos dados daí
CRGB leds[NUM_STRIPS * NUM_LEDS];
String inData;
uint8_t FPS = 100; //FRAMES_PER_SECOND
uint8_t SPARKING = 150;
uint8_t COOLING = 90;
uint8_t BRIGHTNESS = 100;
uint8_t csRGB[4][3] = {{0, 0, 0}, {255, 0, 0}, {255, 127, 0}, {255, 255, 255}};
unsigned long previousMillis = 0;
bool change = false;
//se true vamos guardar na EEPROM.
unsigned long changeMillis = 0;
//alterações serão guardadas 1 minuto após nenhuma alteração ser aplicada para evitar desgaste da EEPROM.
bool initSetup = true;
CRGBPalette16 gPal;
ESP8266WebServer server(80); //Objeto servidor web. Escutará na porta 80 (padrão para HTTP)
void setup() {
EEPROM.begin(200);
cWiFi();
setupFastLED();
loadConfig();
gPal = CRGBPalette16(
CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]),
CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]),
CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),
CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
}
inline void setupFastLED() {
delay(1000); // sanity delay
FastLED.addLeds<CHIPSET, DATA_PIN, COLOR_ORDER>(leds, NUM_STRIPS * NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
}
void loop() {
server.handleClient(); //Tratamento de pedidos recebidos
if (change) {
if (millis() - changeMillis > 60000) {
change = false;
saveToEEPROM();
}
}
fire();
FastLED.show();
FastLED.delay(1000 / FPS);
}
void Fire2012WithPalette(int stripNo) {
static byte heat[NUM_STRIPS][NUM_LEDS];
// Passo 1. Arrefecer cada célula um pouco
for( int i = 0; i < NUM_LEDS; i++) {
heat[stripNo][i] = qsub8( heat[stripNo][i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
}
// Passo 2. O calor de cada célula 'sobe' e difunde um pouco
for( int k= NUM_LEDS - 1; k >= 2; k--) {
heat[stripNo][k] = (heat[stripNo][k - 1] + heat[stripNo][k - 2] + heat[stripNo][k - 2] ) / 3;
}
// Passo 3. Acender aleatoriamente novas 'faíscas' de calor perto da base
if( random8() < SPARKING ) {
int y = random8(5);
heat[stripNo][y] = qadd8( heat[stripNo][y], random8(160,200) );
}
// Passo 4. Mapear de células de calor para cores de LED
for( int j = 0; j < NUM_LEDS; j++) {
// Escalar o valor de calor de 0-255 para 0-240
// para melhores resultados com paletas de cores.
byte colorindex = scale8( heat[stripNo][j], 240);
CRGB color = ColorFromPalette( gPal, colorindex);
leds[j+stripNo*NUM_LEDS] = color;
}
}
void fire(){
for (int i=0; i<NUM_STRIPS; i++){
Fire2012WithPalette(i);
}
}
int str2int(String InputStr) {
return InputStr.toInt();
}
boolean EveryNSec(uint8_t period) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= period * 1000) {
previousMillis = currentMillis;
return true;
} else {
return false;
}
}
void EEPROMupdate(byte address, byte value) {
if (EEPROM.read(address) != value) {
EEPROM.write(address, value);
EEPROM.commit();
}
return;
}
void saveToEEPROM() {
EEPROMupdate(BriAdr, BRIGHTNESS);
EEPROMupdate(FpsAdr, FPS);
EEPROMupdate(SparkingAdr, SPARKING);
EEPROMupdate(CoolingAdr, COOLING);
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t j = 0; j < 3; j++) {
EEPROMupdate((i * 3 + j), csRGB[i][j]);
}
}
}
void handleCS0Change(){
csRGB[0][0] = str2int(server.arg("R"));
csRGB[0][1] = str2int(server.arg("G"));
csRGB[0][2] = str2int(server.arg("B"));
gPal = CRGBPalette16(
CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]),
CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]),
CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),
CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
changeMillis = millis();
change = true;
}
void handleCS1Change(){
csRGB[1][0] = str2int(server.arg("R"));
csRGB[1][1] = str2int(server.arg("G"));
csRGB[1][2] = str2int(server.arg("B"));
gPal = CRGBPalette16(
CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]),
CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]),
CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),
CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
changeMillis = millis();
change = true;
}
void handleCS2Change(){
csRGB[2][0] = str2int(server.arg("R"));
csRGB[2][1] = str2int(server.arg("G"));
csRGB[2][2] = str2int(server.arg("B"));
gPal = CRGBPalette16(
CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]),
CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]),
CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),
CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
changeMillis = millis();
change = true;
}
void handleCS3Change(){
csRGB[3][0] = str2int(server.arg("R"));
csRGB[3][1] = str2int(server.arg("G"));
csRGB[3][2] = str2int(server.arg("B"));
gPal = CRGBPalette16(
CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]),
CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]),
CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),
CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
changeMillis = millis();
change = true;
}
void handleConf() {
if (server.arg("brightness") != "") {
BRIGHTNESS = str2int(server.arg("brightness"));
FastLED.setBrightness(BRIGHTNESS);
changeMillis = millis();
change = true;
}
if (server.arg("fps") != "") {
FPS = str2int(server.arg("fps"));
changeMillis = millis();
change = true;
}
if (server.arg("sparking") != "") {
SPARKING = str2int(server.arg("sparking"));
changeMillis = millis();
change = true;
}
if (server.arg("cooling") != "") {
COOLING = str2int(server.arg("cooling"));
changeMillis = millis();
change = true;
}
server.sendHeader("Connection", "close");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "");
}
void loadConfig() {
if (EEPROM.read(EEPROMCheckAdr) == 250) {
BRIGHTNESS = EEPROM.read(BriAdr);
SPARKING = EEPROM.read(SparkingAdr);
COOLING = EEPROM.read(CoolingAdr);
FPS = EEPROM.read(FpsAdr);
if (FPS == 0) FPS = 100;
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t j = 0; j < 3; j++) {
csRGB[i][j] = EEPROM.read(i * 3 + j);
}
}
}else{
EEPROMupdate(BriAdr,BRIGHTNESS);
EEPROMupdate(FpsAdr,FPS);
EEPROMupdate(CoolingAdr,COOLING);
EEPROMupdate(SparkingAdr, SPARKING);
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t j = 0; j < 3; j++) {
EEPROMupdate((i*3+j) , csRGB[i][j]);
}
}
EEPROMupdate(EEPROMCheckAdr, 250);
}
}
void cWiFi() {
WiFi.softAP("ElectroPeak's Flame", "");
//defina uma password aqui se quiser, ex: WiFi.softAP("ElectroPeak's Flame", "12345678");
IPAddress myIP = WiFi.softAPIP();
server.on("/cs0", handleCS0Change);
server.on("/cs1", handleCS1Change);
server.on("/cs2", handleCS2Change);
server.on("/cs3", handleCS3Change);
server.on("/conf", handleConf);
server.serveStatic("/", SPIFFS, "/", "max-age=86400");
server.begin(); //Iniciar o servidor
}
Para controlar o "aspeto" do fogo há duas variáveis para brincar: SPARKING e COOLING, que pode controlar dinamicamente no software de controlo carregado no SPIFFS ou na app Android que pode baixar. Também pode controlar FPS aqui.

A cor do fogo é controlada com uma paleta de cores que também é alterável através do software de controlo (através de 4 pontos de cor). Basta clicar/tocar em cada círculo de cor que representa um ponto de cor para definir a cor, depois de definir a cor clique em fechar para fechar o diálogo e ver a alteração.

Como Carregar para SPIFFS?
Para carregar os ficheiros para a memória SPIFFS usando Arduino IDE, primeiro precisa de criar uma pasta chamada "data" dentro da pasta do sketch e colocar todos os ficheiros que quer carregar nessa pasta. O ficheiro carregado aqui contém tanto o sketch como esta pasta.
Em seguida, precisa do plugin Arduino ESP8266 filesystem uploader para Arduino. Siga as instruções na página do Github e instale o plugin. Quando instalado, encontrará ESP8266 Sketch Data Upload no menu tools. Coloque o seu ESP em modo de programação e clique nisso. Tenha paciência e deixe os ficheiros carregar, isso pode demorar um pouco. Nota: defina "upload speed" para 921600 para tornar mais rápido.

Como Funciona?
O sketch carregado na placa ESP8266 cria um servidor web nesse dispositivo, que responde aos pedidos enviados pela app. A app simplesmente envia pedidos GET para o servidor (ESP8266). Os dados de cor para criar a paleta são enviados como argumentos no pedido GET, o mesmo vale para outros parâmetros como os parâmetros Sparking e Cooling.
Por exemplo, para definir o brilho, o seguinte pedido é enviado pela app:
https://192.168.4.1/conf?brightness=224
Existe um manipulador para este pedido no sketch que, ao receber este pedido, define o brilho. Reveja o código para saber mais.
App Android
A app Android foi criada usando Phonegap. É uma tecnologia que permite criar apps móveis multiplataforma usando tecnologias web (HTML, CSS, Javascript). Pode obter o código fonte visitando esta página.
Pode ler este e outros tutoriais incríveis no site oficial da ElectroPeak
Código
- Código do Efeito Fogo
- Sketch e pasta Data
Código do Efeito Fogo
// Código completo disponível acima na secção "Código"
Sketch e pasta Data
Este ficheiro zip contém tanto o ficheiro sketch como a pasta data (upload SPIFFS)
Sem pré-visualização (apenas download).
Peças Personalizadas e Caixas
- Ficheiro APK da app Android:
eps_flame_android_u5Zy5Bksvp.apk
Processo de manufatura
- Aproveitando IoT para Detecção Precoce e Prevenção de Incêndios Florestais
- Construa um Sistema Rápido e Confiável de Detecção de Incêndio com Samsung SAMI, Arduino UNO e Raspberry Pi
- Construa um Detector de Choro de Bebê Econômico com Raspberry Pi – Guia DIY
- Danos por Incêndio e Prevenção: Estratégias Especializadas para Proteger Vidas e Propriedades
- Revolucionando Combate a Incêndios: Como IoT Aumenta Segurança, Resposta e Resgate
- iOS vs. Android: Qual Plataforma Oferece Segurança Superior para Apps Enterprise?
- Dominando o Método strip() do Python: Guia Completo e Exemplos Práticos
- Axiom Equipment Group e Patrocinadores Comunitários Doam $11.000 ao Corpo de Bombeiros de Oxbow
- Contador Inteligente de Pessoas Controlado via App Android
- Integrando Sensor de Impressão Digital Capacitivo DFRobot com Arduino ou ESP8266