RGB-LED Strip als Temperaturanzeige

Hallo zusammen,

ich habe nach sehr langer Suche endlich ein Projekt gefunden, das ich zur farblichen Temperaturanzeige verwenden kann.

Hier möchte ich auch erst mal meinen Dank an “dasaweb” aussprechen, aus dessen Feder die Schaltung und der verwendete Code stammt.

Quelle: Arduino-Bastelei: LED-Spielereien | dasaweb

Beschreibung:
es soll eine LED-Strip mit 32LED (1m - WS2801) als Temperaturanzeige verwendet werden.
Folgende Modi sind von dasaweb programmiert worden:

7Modi:

Manuelle Farbsteuerung: Mit den vier Potis kann die Helligkeit des Strips und die Farbzusammensetzung (RGB = rot, grün, blau) eingestellt werden. Änderungen betreffen nicht sofort den ganzen Strip, sondern wandern vom Anfang her über den Strip.
Temperatur-Steuerung: Abhängig von der Zimmertemperatur ändert der Strip seine Farbe von blau (kalt) hin zu rot (warm).
Lautstärke-Steuerung: Der Strip fungiert als Lautstärkeanzeige für Musik: Je lauter die Musik, desto mehr LEDs entlang des Strips leuchten. Außerdem ändert sich mit der Lautstärke auch die Farbe.
Rainbow: Farbverläufe (wie sie eigentlich keiner sehen will) mäandern über den Strip.
DiscoDsicoPartyParty: Zum Bekloppt-Werden: Zufälliges Lichter-Zucken auf allen Kanälen. Die Farbenanteile und die Helligkeit können eingestellt werden.
Volle Helligkeit: Alle LEDs auf weiß und volle Helligkeit. Nichts zu steuern.
LEDs aus: Wie der Name schon sagt, einfach alles aus.

Der Code dazu:
(siehe Anhang: code7modi.txt)

Die Schaltung dazu sieht in etwa so aus:
(siehe Anhang: Schaltung.jpg)

Zur Verwendung sollen ausgewählte Modi kommen.

4Modi:

Manuelle Farbsteuerung: Mit den vier Potis kann die Helligkeit des Strips und die Farbzusammensetzung (RGB = rot, grün, blau) eingestellt werden. Änderungen betreffen nicht sofort den ganzen Strip, sondern wandern vom Anfang her über den Strip.
Temperatur-Steuerung: Abhängig von der Zimmertemperatur ändert der Strip seine Farbe von blau (kalt) hin zu rot (warm).
Volle Helligkeit: Alle LEDs auf weiß und volle Helligkeit. Nichts zu steuern.
LEDs aus: Wie der Name schon sagt, einfach alles aus.

Hierzu wurde der Code angepasst:
(siehe Anhang: code4modi.txt)

Nun zu meinen Fragen bzw. Hilfegesuch:

Die Steuerung soll für eine temperaturgesteuerte RGB-Beleuchtung meines NAS einsetzt werden.
Hierzu benötige ich natürlich nur einen Teil der vorhandenen Modi (1.Manual, 2. Temperatur, 3. AllOn und 4. AllOff).
Zwischenzeitlich habe ich einige veränderte Sketches abgespeichert, komme aber irgendwie nicht weiter.

Im ColorModusTemperature habe ich das Problem, dass ich zwar Tmin und Tmax verändern kann (30 bzw. 45) aber schon bei der Display Anzeige von ca. 31:40C wird der Strip auf „Gelb“ gesetzt, obwohl dies doch erst bei über 45:00 passieren sollte. Auch bei einer Anzeige von 30:60
ist der Strip schon feuerrot. Ändert die Farbe in 00:10C -Schritten.
Die Grenze „weiß-blau“ ist relativ stabil bei der angegebene Tmin (30:00).

Auch wenn ich nur an dem original Code die Tmin und Tmax ändere verhält sich die Steuerung so wie beschrieben. Einziger Unterschied ist, dass ich einen Strip mit nur 1m, also 32 LED dran habe, dies aber in den Variablen geändert habe.

Kann mir hier jemand behilflich sein, etwas Licht ins Dunkel zu bringen?

  1. Woran kann es liegen, dass die Steuerung schon auf 1/10C so schnell reagiert, bzw wo könnte ich hier ansetzen um es zu ändern?

  2. Die verwendeten Poti haben einen Werte von 25k; ist das unter Umständen einen Einflussquelle?

Verständnisfrage:
3. Welchen Zweck hat der Abschnitt „Gefühlte Temp. und Echte Temp. ?
Ich bräuchte nur die eine von DHT22 gemessen wird. Wo kann ich den Code so abändern, dass nur eine Temp Gültigkeit hat. Oder muss das so bleiben?

Danke euch schon mal für die Unterstützung und Tipps!

Grüße Max

code7modi.txt (13.3 KB)

code4modi.txt (9.04 KB)

Der einfachste Weg wäre doch, wenn Du den von Dir so hoch gelobten Autor des Sketches fragen würdest. Der kennt seinen Code und muss sich nicht erst einarbeiten.

Gruß Tommy

Hallo Tommy,

das hatte ich schon versucht!
Das Projekt existiert so nicht mehr, da er sich nun mit Farbräumen etc. beschäftigt.

Letztendlich wollte ich dann auch selbst was hin bekommen, so dass ich auch den Code verstehe und ggf. verändern kann.

Gruß Max

maxmaschine:
Letztendlich wollte ich dann auch selbst was hin bekommen, so dass ich auch den Code verstehe und ggf. verändern kann.

Das ist doch ein sehr guter Ansatz. Warum verfolgst Du den nicht weiter?

Lerne den vorhandenen Code verstehen. Referenz1 und Referenz 2 werden Dir dabei helfen.

Wenn Du grundlegend verstanden hast, was der Code macht, kannst Du das raus werfen, was Du nicht brauchst.
Immer nur überschaubare Änderungen vornehmen und den vorherigen Stand sichern.

Gruß Tommy

Da stimme ich dir zu.
Danke erst mal für die Links… so ein bisschen habe ich dann schon Grundkenntnisse, weshalb ich ja auch den code4modi.txt schon angepasst habe.
Aber genau im für mich wichtigsten Bereich “der Temperatursteuerung” hänge ich!

void ColorModusTemperature(int modusOK) {
 
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  dht.readHumidity();
  dht.readTemperature();
 
  // Gemessene Werte auf seriellen Monitor ausgeben:
  Serial.print("Feucht: "); Serial.print(dht.humidity); Serial.print(" %\t\t");
  Serial.print("Temp: "); Serial.print(dht.temperature_C); Serial.print(" *C\t");
  Serial.print("gef. Temp: "); Serial.print(dht.computeHeatIndex_C()); Serial.println(" *C\t");    // Heat index: https://de.wikipedia.org/wiki/Hitzeindex
 
  // GEFÜHLTE Temperatur auf Display ausgeben:
  //display.showNumberDec(dht.computeHeatIndex_C()*100, false);
  // ECHTE Temperatur auf Display ausgeben:
  display.showNumberDec(dht.temperature_C*100, false);
  // Darstellung mit Doppelpunkt (statt Komma), besser als nichts:  
  uint8_t segto;
  //segto = 0x80 | display.encodeDigit((int)(dht.computeHeatIndex_C())%10);
  segto = 0x80 | display.encodeDigit((int)(dht.temperature_C)%10);
  display.setSegments(&segto, 1, 1);
   
   
 
  float T     = dht.computeHeatIndex_C();
  float Tmin  = 10;
  float Tmax  = 35;
 
  float r = 0;
  float g = 0;
  float b = 0;
   
  // Linearer Verlauf:
  // - Bei Tmin ist die Farbe nur blau
  // - Bei Tmax ist die Farbe nur rot
  // - Unter Tmin ist die Farbe weiß
  // - Über Tmax ist die Farbe gelb
   
  if (T < Tmin) { r = 1; g = 1; b = 1; } else if (T > Tmax) {
    r = 1;
    g = .5;
    b = 0;
  } else {
    r = (T - Tmin) / (Tmax - Tmin);
    g = 0;
    b = (T - Tmax) / (Tmin - Tmax);
  }
//  Serial.print("R = "); Serial.print(r); Serial.print("\t");
//  Serial.print("G = "); Serial.print(g); Serial.print("\t");
//  Serial.print("B = "); Serial.print(b); Serial.print("\t\n"); 
   
  int i;
  for (i=0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i,  Color(r * analogRead(potBrightPin) / 4, g * analogRead(potBrightPin) / 4, b * analogRead(potBrightPin) / 4));
 
    // INTERRUPT EINBAUEN:
    if ((i%100) == 0) Serial.print("");
    if (modus != modusOK) return;
     
  }
  strip.show();   // write all the pixels out
 
  //delay(2000);
}
 

void ColorModusAllOn(int modusOK, uint8_t wait) {
  int i;
  for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Color(255, 255, 255));
      strip.show();
      delay(wait);
   
      // INTERRUPT EINBAUEN:
      if ((i%100) == 0) Serial.print("");
      if (modus != modusOK) return;
     
  }
}
  1. warum ändert sich die Farbe relativ schnell von blau auf rot im 1/10C Stufen; und ist bei eingestellter Tmin 30C schon bei 31,60C feuerrot, wenn Tmax 45,0C eingestellt ist.
  2. für welchen Zweck brauche ich die gefühlte und die echte Temperatur? …m.E. würde mir hier die Echte ausreichen.

Gib Dir die Zwischenstände und Werte Deiner Farbberechnung auf dem seriellen Monitor aus, dann kannst Du sehen, was passiert und es gemäß Deinen Wünschen anpassen.

Da wir Deine Hardware nicht haben, musst Du das selbst machen.

Gruß Tommy

Hallo,

beschreibe doch noch mal was Du jetzt genau vor hast. Temperatur der NAS darstellen. ? Muss ich mir das als Farbbalken vorstellen der mit steigender Temperatur länger und von blau nach rot wechselt. ?

ich denke du machst dich am besten von dem Ballast des vorhanen Sketches frei und fängst neu an. Schau dir z.B die einfachen Beispiele der FastLED Lib an . Wie steuert man eine einzelne LED an, wie zwei... , wie stellt man die Farben ein. Dann musst Du dir z.B den Temperaturbereich 20-60grad= 1-32LED und die Skala dazu überlegen. Das gleiche für die Farben.

Heinz

…also mein Vorhaben:

habe zwei 160mm Lüfter im NAS- Schrank sitzen die per PWM in der Drehzahl temperaturabhängig gesteuert werden. Im Außenring der Lüfter ist bis jetzt je ein roter LED-Strip verbaut, der je nach Drehzahl heller oder dunkler leuchtet. Der Rote Strip wird dann durch einen RGB-Strip WS2801 ersetzt.

Da der Umfang beider Lüfter ca. 1m ist (160mm * 3,14 *2) habe ich nur 32LED und nicht 160 wie im Original von dasaweb.

Der RGB-Strip soll unterhalb Tmin (<30C) weiß leuchten,
bei Tmin (=30C) blau werden,
dann zwischen Tmin und Tmax stufenlos violett leuchten,
bis rot Tmax (=45C) erreicht ist
und über Tmax (>45C) dann gelb leuchten.

D.H. es soll kein Balken entstehen der größer oder kleiner (ähnlich eine Audio-Level Anzeige) wird, sondern alle LED die Farbe temperaturgesteuert ändern.

Der Eingabeparameter ist die Temperatur.

Und meine Problem ist die Funktion bzw. der Code.

Ich habe den Bereich von dasaweb zwar angeschaut, verstehe aber nicht warum der Gefühle und Echte Temp verwendet und wo genau im Code (Funktion) die Berechnung stattfindet.

Das müsste doch der Teil ab “if” sein???

if (T < Tmin) { r = 1; g = 1; b = 1; } else if (T > Tmax) {
r = 1;
g = .5;
b = 0;
} else {
r = (T - Tmin) / (Tmax - Tmin);
g = 0;
b = (T - Tmax) / (Tmin - Tmax);
}
// Serial.print(“R = “); Serial.print(r); Serial.print(”\t”);
// Serial.print(“G = “); Serial.print(g); Serial.print(”\t”);
// Serial.print(“B = “); Serial.print(b); Serial.print(”\t\n”);

Anmerkung zur Quelle: Wenn ein Vater seinem Sohn was bastelt, dann ist das natürlich wunderbar, wegen Zeitdruck und kurzer Lebensdauer aber nicht unbedingt die hohe Kunst des Programmierens. So erhält die Verwendung von delay() im Zusammenhang mit Tastenerkennung mittels Interrupt durch mich keinen Beifall. Auch ist ein UNO gegenüber so einem LED-Streifen recht langsam, weshalb die Framerate mittels Hardware-SPI erhöht werden kann:

// Hardware SPI is a little faster, but must be wired to specific pins
// (Arduino Uno = pin 11 for data, 13 for clock, other boards are different).
Adafruit_DotStar strip(NUMPIXELS, DOTSTAR_BRG);

Anstelle Adafruit_WS2801 habe ich bislang immer Adafruit_DotStar verwendet. Wie die sich unterscheiden, entzieht sich daher meiner Kenntnis.

Zum Testen habe ich einen Nano mit WS2815 zur Verfügung. Abgesehen von der Initialisierung sollte das aber gleich sein.

Da mir ein Temperatursensor fehlt und eine Simulation damit auch schwierig wäre, verwende ich stattdessen ein Poti an A0. Verkürzt auf Deine Anzeige sieht das bei mir dann so aus:

// getestet mit Nano und WS2815
#include <Adafruit_NeoPixel.h> // include the Neopixel Library in this Sketch
#define PIN 11 // This is the Arduino Pin controlling the LEDstrip.
#define NUMPIXELS 32
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show();   // Update LED contents, to start they are all 'off'

  // Ausgabe auf seriellem Monitor:
  Serial.begin(9600);
  Serial.println("Temp\tRed\tGreen\tBlue");
}

void loop() {
  ColorModusTemperature();
}

void ColorModusTemperature() {
  const uint32_t anzeigeintervall = 1000; // in Millisekunden
  static uint32_t vorhin = 0;
  if (millis() - vorhin >= anzeigeintervall) {
    vorhin = millis();
    const byte potTempPin = A0;
    uint16_t potTemp   = analogRead(potTempPin); // Zehntel Grad C

    // Gemessene Werte auf seriellen Monitor ausgeben:
    Serial.print("Temp: "); Serial.print(potTemp / 10.0, 1); Serial.print(" *C\t");

    uint16_t T     = potTemp;  // Zehntel Grad C
    uint16_t Tmin  = 100;      // Zehntel Grad C
    uint16_t Tmax  = 350;      // Zehntel Grad C

    byte r = 0;
    byte g = 0;
    byte b = 0;

    // Linearer Verlauf:
    // - Bei Tmin ist die Farbe nur blau
    // - Bei Tmax ist die Farbe nur rot
    // - Unter Tmin ist die Farbe weiß
    // - Über Tmax ist die Farbe gelb

    if (T < Tmin) {
      r = 255;
      g = 255;
      b = 255;
    }
    else if (T > Tmax) {
      r = 255;
      g = 128;
      b = 0;
    }
    else {
      r = 255 * (T - Tmin) / (Tmax - Tmin);
      g = 0;
      b = 255 * (Tmax - T) / (Tmax - Tmin);
    }
    Serial.print("R = "); Serial.print(r); Serial.print("\t");
    Serial.print("G = "); Serial.print(g); Serial.print("\t");
    Serial.print("B = "); Serial.print(b); Serial.print("\t\n");
    strip.fill(strip.Color(r , g , b ), 0, strip.numPixels());
    strip.show();   // write all the pixels out
  }
}

Möglicherweise nutzt es Dir.

Ein anderer Farbraum geht mit ColorHSV(uint16_t hue, uint8_t sat=255, uint8_t val=255);

Serielle Ausgaben haben in Interrupts auch nichts verloren

Und delay() funktioniert darin schlichtweg nicht, da keine anderen Interrupts mehr kommen können

Hi agmue,

das ist ja super nett, dass du der Code gleich umschreibst...
Ich werde das mal kurz nachbauen und auch mit einem Poti erst testen.

Nach erfolgreichem Test werde ich mich dann an der Temp-Sensor machen und versuchen diesen einzubauen.

Ich glaube hier bin ich genau richtig gelandet um das Projekt zu realisieren.

:wink:

Guten Morgen agmue,

ich habe gestern noch experimentiert.

Da ich den WS2815 Strip nicht habe, hatte ich einfach mal auf die Monitor Ausgabe gesetzt und hatte keinen Strip angeschlossen.
Poti Wert 25k:
wenn ich den Schleifer auf A0 gegen GND hänge, bekomme ich am Monitor:

Temp Red Green Blue
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255

wenn der Schleifer an A0 gegen 5V hängt, bekomme ich am Monitor:

Temp: 102.3 *C R = 255 G = 128 B = 0
Temp: 102.3 *C R = 255 G = 128 B = 0
Temp: 102.3 *C R = 255 G = 128 B = 0

wenn ich dann A0 einfach offen lasse, wird am Monitor angezeigt:

Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 0.0 *C R = 255 G = 255 B = 255
Temp: 28.9 *C R = 192 G = 0 B = 62
Temp: 39.2 *C R = 255 G = 128 B = 0
Temp: 64.1 *C R = 255 G = 128 B = 0
Temp: 67.8 *C R = 255 G = 128 B = 0
Temp: 87.5 *C R = 255 G = 128 B = 0
Temp: 91.8 *C R = 255 G = 128 B = 0
Temp: 100.4 *C R = 255 G = 128 B = 0
Temp: 93.6 *C R = 255 G = 128 B = 0
Temp: 88.3 *C R = 255 G = 128 B = 0
Temp: 82.3 *C R = 255 G = 128 B = 0
Temp: 79.8 *C R = 255 G = 128 B = 0
Temp: 66.2 *C R = 255 G = 128 B = 0
Temp: 63.6 *C R = 255 G = 128 B = 0

und der Wert verändert sich laufend ohne Eingriff!

nun ein paar Fragen!

-welchen Poti Wert hast du verwendet?
-wie angeschlossen (5V und GND an Poti und A0 an Schleifer)?

-wie würdest du den DHT22 hier einbauen?

Danke dir schon mal!
Bis später dann

Gruß Max

maxmaschine:
-welchen Poti Wert hast du verwendet?

10 kΩ

maxmaschine:
-wie angeschlossen (5V und GND an Poti und A0 an Schleifer)?

Ja.

maxmaschine:
-wie würdest du den DHT22 hier einbauen?

So einen Sensor habe ich nicht, aber mein Kandidat wäre dht.temperature_C.

Ok, das werde ich dann mal testen.

versuche dann auch gleich mal den DHT22 einzubauen... mal sehen ob es funktioniert.

Da ich nur den WS2801 derzeit habe, werde ich entweder ohne LED testen (nur serieller Monitor) oder den WS2801 auch versuchen einzubauen!

Ich denke, dass es zuerst wichtig ist am Seriellen Monitor die Funktion des DHT22 lauffähig zu bekommen.
Zusätzlich kann ich mir ohne Strip auch das ext. Netzteil vorerst sparen :wink: :wink:

Danke dir

Bis später
Max

...jetzt habe ich doch noch gleich eine Frage:

den DHT22 habe ich mal wie beschrieben eingebunden.

#include "cactus_io_DHT22.h"      // Includes für Temp-Sensor:
#define DHT22_PIN 4               // Data-Pin des Temp-Sensors:
DHT22 dht(DHT22_PIN);             // Sensor initialisieren:

nun habe ich aber das Problem, wo ich dht.temperature_C einsetze?

Überall wo bei dir der potTemp eingesetzt ist, natürlich mit Pin = 4

void ColorModusTemperature() {
  const uint32_t anzeigeintervall = 1000; // in Millisekunden
  static uint32_t vorhin = 0;
  if (millis() - vorhin >= anzeigeintervall) {
    vorhin = millis();
    const byte potTempPin = A0;
    uint16_t potTemp   = analogRead(potTempPin); // Zehntel Grad C

    // Gemessene Werte auf seriellen Monitor ausgeben:
    Serial.print("Temp: "); Serial.print(potTemp / 10.0, 1); Serial.print(" *C\t");

    uint16_t T     = potTemp;  // Zehntel Grad C
    uint16_t Tmin  = 100;      // Zehntel Grad C
    uint16_t Tmax  = 350;      // Zehntel Grad C

oder muss ich da noch mehr aus dem ursprünglichen Code rausholen?

cactus_io_DHT22.h ist keine mir bekannte Datei.

Man muß mit dht.readTemperature(); erst messen und dann den Meßwert mittels wert = dht.temperature_C; in eine Variable übertragen.

Eventuell also uint16_t potTemp = 10 * dht.temperature_C; // Zehntel Grad C

:confused: ...ok , ich sehe schon; das wird Wochen dauern... aber man lernt dadurch auch was. :slight_smile:

Ich sehe gerade dass der WS2815 ein 12V Strip ist. Dann muss ich auf jeden mit Netzteil arbeiten.

Wie wird der dann an Nano angeschlossen?
Grün = PIN 11
Blau = offen
Rot+ und Weiß- = ext. Netz 12V
Masse ext. Netz und GND verbinden?

maxmaschine:
:confused: ...ok , ich sehe schon; das wird Wochen dauern... aber man lernt dadurch auch was. :slight_smile:

Deswegen machst Du das doch ;D

maxmaschine:
Ich sehe gerade dass der WS2815 ein 12V Strip ist. Dann muss ich auf jeden mit Netzteil arbeiten.

Wie wird der dann an Nano angeschlossen?

Grün = Widerstand - PIN 11
Blau = GND
Rot = 12 V Netzteil
Weiß = GND Netzteil und Nano

Vorteil ist der geringere Strom von maximal 10 - 15 mA gegenüber 60 mA je Pixel. Das bringt Dir bei 32 Pixeln aber keinen Vorteil.

Ändere einfach die ersten Zeilen auf Deinen Typ.

agmue:
Deswegen machst Du das doch ;D

klar, man lernt nie aus! :wink:

agmue:
Grün = Widerstand - PIN 11

Ändere einfach die ersten Zeilen auf Deinen Typ.

welchen R-Wert setze ich ein? bzw. wie berechne ich diesen?
das gilt ja wahrscheinlich auch wenn ich auf den WS2801 ändere?