Several “fire programs” for our mood lantern

So far, our lantern works quite well, and can be remotely controlled with the basic functions. However, and I had already let this shine through in the previous part, today in the last part of our mood lantern series we will "pimp" our lantern a bit and donate it not only a flicker program, but a total of 5 different fire simulation programs, which can also be selected individually by remote control!


The code can and should! Of course, also be supplemented by own simulation algorithms, so that the inclined reader has an infinite number of possibilities to let his own creativity run free. But let's deal with the 5 algorithms that I have built in and which are derived from each other.

  • Program 1: No flickering, rapidly changing different flame temperature.
  • Program 2: No flickering, permanent equal flame temperature. Standing light.
  • Program 3: Strong, frequent flickering, rapidly changing different flame temperature.
  • Program 4: Strong, rare flickering, same flame temperature.
  • Program 5: mild, frequent flickering, rapidly changing different flame temperature.
  • Program 6: Strong, rare flickering, rapidly changing different flame temperature.

Program 5 is the "standard program" from the 2 part of this Maker series. 
The inclined reader will probably have already recognized that this different simulation algorithms are called or controlled via the "switch-case" structure. This happens depending on the read-in remote control code in the following section:

 

switch (IRCode)
{
case -522182433: " In my case 1 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 1;
}
break;
case -522149793: " In my case 2 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 2;
}
break;
case -522166113: " In my case 3 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 3;
}
break;
case -522186513: " In my case 4 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 4;
}
break;
case -522153873: " In my case 5 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 5;
}
break;
case -522173873: " In my case 6 on my TV - Remote
{
FireON = ! FireON;
FireSequence = 5;
}
break;

Default:
Serial.println (IRCode);
break;
}

 

In order to make the whole thing work with our own remote control, we only have to use the serial interface first (also works with the code from part 2) to output the remote control codes of 5 buttons, which we want to use to control the lantern:

Part 3 - Serial Output

We upload the following code to our Arduino after entering the numbers in the case statement accordingly:

 

 

#include <Adafruit_NeoPixel.H>
#include <IRremote.H>

#define Pin        6  Which pin on the Arduino is connected to the NeoPixels?
#define RECV_PIN 11  define IR input pin on Arduino 
#define NUMPIXELS 12 How many NeoPixels are attached to the Arduino? Popular NeoPixel ring size

Adafruit_NeoPixel pixels(NUMPIXELS, Pin, NEO_GRB + NEO_KHZ800);
IRrecv irrecv(RECV_PIN);
decode_results Results; decode_results class is defined in IRremote.h

Long FirelastTime = 0;
Long IRlastTime = 0;
Long TimerlastTime = 0;
Int interval;
Long IRCode = 0;
Long OLDIRCode = 0;
Bool FireON = False;
Bool FireOFF = False;
Byte FireSequence = 0;

Void Setup()
{   Serial.Begin(115200);   while (!Serial);   wait until Serial is established - required on some platforms   irrecv.enableIRIn(); Start the receiver   pixels.Begin(); INITIALIZE NeoPixels   pixels.Show(); Initialize all pixels to 'off'   interval = 300;   randomSeed(analogRead(0));
}

Void SimulateFire (Bool On, byte FireSq)
{   byte LightValue[NUMPIXELS * 3];   if (millis() - FirelastTime >= interval)   {     if (On)     {       FireOFF = false;       FirelastTime = millis();       interval = 200;       if (FireSq == 1)       {         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           LightValue[i * 3] = random(200, 255); // 250           LightValue[i * 3 + 1] = random(30, 70); // 50           LightValue[i * 3 + 2] = 0;         }         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }       if (FireSq == 2)       {         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, 250, 50, 0);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }       if (FireSq == 3)       {         interval = random(50, 100);         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           LightValue[i * 3] = random(240, 255); // 250           LightValue[i * 3 + 1] = random(30, 60); // 50           LightValue[i * 3 + 2] = 0;         }         // Switch some lights out         byte LightsOff  = random(0, 6);         for (int i = 0; i < LightsOff; i++)         {           byte Selected = random(NUMPIXELS);           LightValue[Selected * 3] = 0;           LightValue[Selected * 3 + 1] = 0;           LightValue[Selected * 3 + 2] = 0;         }         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }       if (FireSq == 4)       {         interval = random(80);         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           LightValue[i * 3] = 250; //random(240,255); // 250           LightValue[i * 3 + 1] =  50; //random(30,60); // 50           LightValue[i * 3 + 2] = 0;         }         // Switch some lights out if Chance Hit         byte ChanceforLightsOff  = random(0, 40);         if (ChanceforLightsOff > 35)         {           byte LightsOff  = random(5);           for (int i = 0; i < LightsOff; i++)           {             byte Selected = random(NUMPIXELS);             LightValue[Selected * 3] = 0;             LightValue[Selected * 3 + 1] = 0;             LightValue[Selected * 3 + 2] = 0;           }         }         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }       if (FireSq == 5)       {         interval = random(150, 200);         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           LightValue[i * 3] = random(240, 255); // 250           LightValue[i * 3 + 1] = random(30, 60); // 50           LightValue[i * 3 + 2] = 0;         }         // Switch some lights darker         byte LightsOff  = random(0, 4);         for (int i = 0; i < LightsOff; i++)         {           byte Selected = random(NUMPIXELS);           LightValue[Selected * 3] = random(50, 60);           LightValue[Selected * 3 + 1] = random(5, 10);           LightValue[Selected * 3 + 2] = 0;         }         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }       if (FireSq == 6)       {         interval = random(80);         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           LightValue[i * 3] = random(240, 255); // 250           LightValue[i * 3 + 1] = random(40, 60); // 50           LightValue[i * 3 + 2] = 0;         }         // Switch some lights out if Chance Hit         byte ChanceforLightsOff  = random(0, 40);         if (ChanceforLightsOff > 35)         {           byte LightsOff  = random(5);           for (int i = 0; i < LightsOff; i++)           {             byte Selected = random(NUMPIXELS);             LightValue[Selected * 3] = 0;             LightValue[Selected * 3 + 1] = 0;             LightValue[Selected * 3 + 2] = 0;           }         }         for (int i = 0; i < NUMPIXELS; i++)         { // For each pixel...           pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]);         }         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();       }     }     else     {       if (!(FireOFF))       {         pixels.clear();         noInterrupts();         pixels.show();   // Send the updated pixel colors to the hardware.         interrupts();         FireOFF = true;       }     }   }
}

long ReceiveIrCommand ()
{   long result = 0;   if (irrecv.decode(&results))   {     result = results.value;     irrecv.resume(); // Receive the next value     return result;   }   Return 0 ;
}

Void IRCommandProcessor (Long IrCommand)
{   If (IRCode == OLDIRCode) {     TimerlastTime = millis(); Some stuff about debouncing IR Remote   }   If (millis() - TimerlastTime >= 300) {     OLDIRCode = 0 ; Some stuff about debouncing IR Remote   }   If ((IRCode < -1) & (IRCode != OLDIRCode) & (IRCode > -600000000) & (IRCode < -500000000))  Valid IR Signal Received   {     OLDIRCode = IRCode;                                           Some stuff about debouncing IR Remote     Switch (IRCode)     {       Case -522182433:        In my case 1 on my TV - Remote         {           FireON = !FireON;           FireSequence = 1;         }         Break;       Case -522149793:        In my case 2 on my TV - Remote         {           FireON = !FireON;           FireSequence = 2;         }         Break;       Case -522166113:        In my case 3 on my TV - Remote         {           FireON = !FireON;           FireSequence = 3;         }         Break;       Case -522186513:        In my case 4 on my TV - Remote         {           FireON = !FireON;           FireSequence = 4;         }         Break;       Case -522153873:        In my case 5 on my TV - Remote         {           FireON = !FireON;           FireSequence = 5;         }         Break;       Case -522178353:        In my case 6 on my TV - Remote         {           FireON = !FireON;           FireSequence = 6;         }         Break;       Default:         Serial.println(IRCode);         Break;     }   }
}

Void Loop()
{   IRCode = ReceiveIrCommand();   IRCommandProcessor(IRCode);   SimulateFire(FireON, FireSequence);
}

 

The function of the buttons has changed somewhat. There is no longer a dedicated button to turn the lantern on and off. Instead, each of the 6 defined buttons can now turn off the lantern again by a further (renewed) actuator, provided that a pause of at least 1 second is observed between the individual keypresses (release the button).

I wish you a lot of fun upgrading your lantern firmware.

 

Für arduinoProjekte für fortgeschrittene

8 comments

Joachim

Joachim

Hallo, mich würde interessieren, was ich an der Programmierung ändern muss, damit der LED bereits mit z.B. Programm 1 startet sobald der Arduino gestartet wird? Habe schon einiges probiert, aber nichts gescheites hinbekommen, außer dauer an….

Ake

Ake

Hallo, was müsste ich am Code ändern, um z.B. immer mit FireSequenz 1 zu starten. Das quasi beim starten des Arduino Programm 1 läuft, ohne das die Fernbedienung benutzt wird…

Bert

Bert

Hallo Tobias,

vielen Dank für Deine Mühe.
Durch den Nachtrag funktioniert es nun PERFEKT &
“Oma’s Windlicht” erstrahlt (buchstäblich) in neuem Glanz :-)

Tobias

Tobias

Hallo bert,

Für Fernbedienungen aus dem Einsteiger KIT verwende bitte im Code statt:

if ((IRCode < -1) & (IRCode != OLDIRCode) ….

den Code:

if ((IRCode > 0) & (IRCode != OLDIRCode)

Die Einsteiger-KIT Fernbedienungen haben ein komplett anderen Codebereich als die “normalen” Fernbedienungen"

Bert

Bert

Hallo Tobias,

Danke für den Tipp UND die tolle Projektidee.
Das mit den Strays hatte ich (Dank Google) herausgefunden, den Hinweis mit den Codes befolgt. Wie befürchtet hat es aber nicht geholfen – denn die Fernbedienung ist keine TV Fernbedienung (damit habe ich es übrigens auch probiert Fabr. LG), sondern eine aus den Einsteigerkits (aus da ist auch der LED Empfänger her) .

Ich kenn mich jetzt (noch) nicht mir der Arduino Programmiersprache aus, aber es sein,
dass da die Auswahlroutine “zu” gründlich ist ?

Anyway – “zum Laufen” habe ich den Aufbau ja bekommen, nur das mit den verschiedenen Lichtstimmungen bekomme ich nicht hin :-(

Da gibt es doch Funktions-/Routine Aufrufe ( void ?) – kannst Du da evtl. einzelne
Code Teile – wie “Programm 1: Kein Flackern, schnell wechselnde unterschiedliche Flammentemperatur” als >> Flacker(); << zum Download einstellen, die dann je nach Ereignis (IR Code) ausgeführt werden ?

Hoffe ich hab mich verständlich ausgedrückt – wie gesagt – was Arduino Programmierung angeht bin ich ein absoluter Neuling :-)

Tobias Kuch

Tobias Kuch

Noch ein Nachtrag: Falls die u.g Änderungen keinen Erfolg bringen, kann es auch helfen die Zeile:
if ((IRCode < -1) & (IRCode != OLDIRCode) & (IRCode > -600000000) & (IRCode < -500000000)) // Valid IR Signal Received
{

in

if ((IRCode < -1) & (IRCode != OLDIRCode) ) // Valid IR Signal Received

zu ändern, um hier das Filtern der IR Codes auf einen Bereich zu unterdrücken, und “alle” Codebereiche damit freizugeben. Dies kann insbesondere bei NICHT-Samsung Fernbedienungen sinnvoll sein.

Tobias

Tobias

Hallo Bert,
Der “Stray”-Fehler ist ein Klassiker. Er wird nicht durch den Code selbst oder ein evtl. Fehler erzeugt, sondern durch Sonderzeichen, die durch den Kopiervorgang in die Arduino IDE eingefügt werden. Umgehen lässt er sich, wenn die Sonderzeichen vor Einfügen in die IDE gelöscht werden. Das kleine Ausgabe der IR Codes erfolgt liegt evtl. daran, das eine ähnliche Fernbedienung genutzt wird, die ich zum Testen des Codes verwendet habe. (Samsung TV). Bei belegten Codes erfolgt keine Ausgabe mehr auf der seriellen Schnittstelle. Bitte ersetzte alle genannten Fernbedienungscodes im Code erst mal durch einen Dummy (Bsp: 111) und teste dann mit einer Schnittstellengeschwindigkeit von 115200 Baud. Gruß

Bert

Bert

Eigentlich ein klasse Projekt, aber bei Code kopieren “Stray” Fehler.
Beim copy & paste vom Quelltext hier auf der Seite kein Fehler.
Dafür wird aber auch im Seriellen Monitor kein IR Code angezeigt
und auch sonst “tut sich nix” .
Mit (angepassten) Programmen wie hier
=> https://funduino.de/nr-11-fernbedienung
wird wenigstens der / die Codes ausgegeben & LED Ring angeschaltet.
Hardware, Aufbau, etc. sollten also OK sein – wo ist der Haken ?

Leave a comment

All comments are moderated before being published