Http Steuerung, Einteilung LED Streifen in Blöcke Programmierfragen

Ahoi,

ich hab ein paar Fragen zu Möglichkeiten, wie ich nen Controller (WeMos D1 mini) vernüftig programmieren könnte bzw. was da als gute Grundlage herhalten könnte. Also vorallem Tipps, wie das elegant möglich wäre.

Ich hab folgendes vor:

Ich habe einen LED Streifen (WS2812b), den ich in einzelne Segmente a 14 Leds unterteilt habe. Aktuell habe ich insgesamt 126 Leds.
Vorgestellt hab ich mir folgendes:

  • Gruppenbildung von jeweils 14 LEDs um dort dann jeweils für die Gruppe Farben, Helligkeit und vielleicht sogar Verlaufsfunktionen einstellen zu können
  • den Streifen als gesamtes mit einem Befehl anpassen zu können
  • das ganze dann über Http Steuern zu können
  • Ideal wäre es die einzelnen Farben als Funktion einstellen zu können, also per Link die einzelnen Farben einstellen zu können und nicht nur vorgefertigte Links.

Meine Fragen dazu wären (mindestens):

Hab einen ganz coolen Sketch von "bitluni" gefunden mit dem man beim ganzen Streifen schon einmal die Farben ändern könnte:

  • Problem ist allerdings, dass er nen RGB Stripe hat und ich einen GBR. Bei einzelnen Farben brauch ich da ja nur die Reihenfolge der Zahlen für die Farben ändern, aber bei bspw. Farbverläufen oder Regenbögen wäre das evtl. was unpraktisch....

Hauptcode gibts im ersten Kommentar war zu lang...

Und dann z.B. die Farbfunktion:

/*
Released under Creative Commons Attribution 4.0
by bitluni 2016
https://creativecommons.org/licenses/by/4.0/
Attribution means you can use it however you like as long you
mention that it's base on my stuff.
I'll be pleased if you'd do it by sharing http://youtube.com/bitlunislab
*/

#include <ESP8266WebServer.h>
#include "LedFunction.h"

const int MAX_LED_COUNT = 124;

class LedStates
{
  public:
  uint8_t values[MAX_LED_COUNT][3] = {{0}};
  int count = 0;
  bool dirty = false;
  Adafruit_NeoPixel &pixels;
  LedFunction *function = 0;
  
  LedStates(Adafruit_NeoPixel &ledPixels)
  :pixels(ledPixels)
  {
    count = pixels.numPixels();
  }

  void setFunction(LedFunction *newFunction)
  {
    if(function)
      delete function;
    function = newFunction;
    if(!function)
      return;
    function->state = this;
  }

  void setRgb(int i, uint8_t r, uint8_t g, uint8_t b)
  {
    values[i][0] = r;
    values[i][1] = g;
    values[i][2] = b;
    dirty = true;
  }

  virtual void render()
  {
    if(function)
      function->render();
  }

  void setValues(LedStates &to)
  {
    for(int i = 0; i < count; i++)
      for(int j = 0; j < 3; j++)
        values[i][j] = to.values[i][j];
    setFunction(to.function);
    to.function = 0;
    dirty = true;
  }

  void commit()
  {
    if(!dirty)
      return;
    for(int i = 0; i < count; i++)
      pixels.setPixelColor(i, pixels.Color(values[i][0], values[i][1], values[i][2]));
    pixels.show();
    dirty = false;
  }

  void fade(LedStates &to, long f0, long f1)
  {
    for(int i = 0; i < count; i++)
      pixels.setPixelColor(i, pixels.Color((values[i][0] * f0 + to.values[i][0] * f1) >> 16, (values[i][1] * f0 + to.values[i][1] * f1) >> 16, (values[i][2] * f0 + to.values[i][2] * f1) >> 16));
    pixels.show();
    dirty = true;
  }
};

Den gesamten Code mit den anderen Funktionen gäbe es hier: GitHub - bitluni/bitluniHomeAutomation

Da wäre meine Frage, wie man da für die 9 einzelne Elemente jeweils einen Bereich anlegen könnte. Könnte ich dann einfach die Farbfunktion noch 9x anlegen und dann nur in der For Schleife ihn nur zwischen 0 und <14 bzw 14 und <28 usw. zählen lassen? Da wäre meine Frage, wie man das dann einbinden könnte und dann über den Server ansteuern könnte.

Könnte ich bei dem Code auch die Reihenfolge der Farben ändern oder zerbombt das dann alles?:smiley:

Hoffe das war jetzt nicht viel zu ausführlich und vielen Dank schonmal den ganzen Quatsch gelesen zu haben.

Chris

/*
Released under Creative Commons Attribution 4.0
by bitluni 2016
https://creativecommons.org/licenses/by/4.0/
Attribution means you can use it however you like as long you
mention that it's base on my stuff.
I'll be pleased if you'd do it by sharing http://youtube.com/bitlunislab
*/

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#include <Adafruit_NeoPixel.h>

#include "PinStates.h"
#include "LedStates.h"
#include "Fader.h"
#include "RainbowFunction.h"
#include "SimpleRGBFunction.h"
#include "SimpleRGBFunction1.h"
#include "SimpleRGBFunction2.h"
#include "WaveFunction.h"
#include "RF.h"

const char* ssid = "Wlan Name";           //
const char* password = "Passwort";  // 

ESP8266WebServer server(80);

const int LED_PIN = D4;
const int LED_COUNT = 126;

const int RF_OSC = 200;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

LedStates currentLedStates(strip);
LedStates targetLedStates(strip);
Fader<LedStates> ledFader(currentLedStates, targetLedStates);
PinStates currentPinStates;
PinStates targetPinStates;
Fader<PinStates> pinFader(currentPinStates, targetPinStates);

void handleRoot() {
  String message = "<html><head></head><body style='font-family: sans-serif; font-size: 12px'>Following functions are available:

";
  message += "<a href='/rainbow?fade=3000'>/rainbow</a> a rainbow animation on LEDs
";
  message += "<a href='/wave?r=255&g=32&b=10&fade=5000'>/wave</a> a slow wave animation on LED on base color specified by arguments: r=<0..255> g=<0..255> b=<0..255>
";
  message += "<a href='/setleds?r=32&g=64&b=32&fade=1000'>/setleds</a> sets LEDs to the color from arguments: r=<0..255> g=<0..255> b=<0..255>
";
  message += "<a href='/ledsoff?fade=500'>/ledsoff</a> turns off LEDs
";
  message += "<a href='/setpins?D1=128&D2=256&D3=512'>/setpins</a> sets to any of the in arguments specified pins (D0..D8) to their PWM values (0..1023). To use them digital: 0=off, 1023=on
";
  message += "<a href='/togglepins'>/togglepins</a> inverts all pin values form pins used before.
";
  message += "<a href='/rf?D=6&t=200&id=28013&channel=0&on=1'>/rf</a> sends a rf code from arguments: D=<0..8> t=<0..1000> id=<0..1048575> channel=<0..2> on=<0..1>. Dx is the pin, t is the optional signal clock(default is 200, works for me)

";
  message += "All functions except togglepins and rf support the argument 'fade' which specifies the milliseconds it takes to fade to the new specified state. ...nice blending ;-)
";
  message += "
Syntax is as follows: http://&ltip>/&ltcommand>?&ltargument1>=&ltvalue1>&&ltargument2>=&ltvalue2>&...
";
  message += "You can click on each link to see an example.

";
  message += "have fun -<a href='http://youtube.com/bitlunislab'>bitluni</a></body></html>";
  server.send(200, "text/html", message);
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

int getArgValue(String name)
{
  for (uint8_t i = 0; i < server.args(); i++)
    if(server.argName(i) == name)
      return server.arg(i).toInt();
  return -1;
}

bool checkFadeAndSetLedFunction(LedFunction *f)
{
  int fade = getArgValue("fade");
  if(fade > -1)
  {
    targetLedStates.setFunction(f);
    ledFader.start(fade);
  }
  else
    currentLedStates.setFunction(f);  
}

void handleRf()
{
 const int pinNumbers[] = {D0, D1, D2, D3, D4, D5, D6, D7, D8};
 int pin = getArgValue("D");
 int t = getArgValue("t");
 if(t == -1) t = RF_OSC;
 int id = getArgValue("id");
 int ch = getArgValue("channel");
 int on = getArgValue("on");
 String out = "rf D";
 out += pin;
 out += " ";
 out += t;
 out += " ";
 out += id;
 out += " ";
 out += ch;
 out += " ";
 out += on;
 pinMode(pinNumbers[pin], OUTPUT);
 for(int i = 0; i < 5; i++)
 rfWriteCode(pinNumbers[pin], t, id, (1 << (ch + 1)) | (on > 0? 1: 0));
 server.send(200, "text/plain", out); 
}

void setup(void){
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  //find it as http://lights.local
  /*if (MDNS.begin("lights")) 
  {
    Serial.println("MDNS responder started");
  }*/
  
  server.on("/", handleRoot);

  server.on("/rainbow", [](){
    server.send(200, "text/plain", "rainbow");
    checkFadeAndSetLedFunction(new RainbowFunction());
  });

  server.on("/wave", [](){
    server.send(200, "text/plain", "wave");
    WaveFunction *f = new WaveFunction();
    f->init(server);
    checkFadeAndSetLedFunction(f);
  });

  server.on("/setleds", [](){
    server.send(200, "text/plain", "setleds");
    SimpleRGBFunction *f = new SimpleRGBFunction();
    f->init(server);
    checkFadeAndSetLedFunction(f);
  });

  server.on("/ledsoff", [](){
    server.send(200, "text/plain", "ledsoff");
    checkFadeAndSetLedFunction(new SimpleRGBFunction());
  });

  server.on("/togglepins", [](){
    server.send(200, "text/plain", "togglepins");
    currentPinStates.toggle();
    currentPinStates.commit();
  });
  
  server.on("/setpins", [](){
    server.send(200, "text/plain", "setpins");
    int fade = getArgValue("fade");
    if(fade > -1)
    {
      targetPinStates.loadValues(server);
      pinFader.start(fade);
    }
    else
    {
      currentPinStates.loadValues(server);
      currentPinStates.commit();
    }
  });

  server.on("/pinsoff", [](){
    server.send(200, "text/plain", "pinsoff");
    currentPinStates.setAllTo(0);
    currentPinStates.commit();
  });

  server.on("/rf", handleRf);
  
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
  
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop(void)
{
  server.handleClient();
  //MDNS.update();
  currentLedStates.render();
  if(ledFader.active)
    targetLedStates.render();
  if(!ledFader.fade())
    currentLedStates.commit();
  pinFader.fade();
}

Schau Dir doch mal die Lib FastLED an. Die bietet viele Möglichkeiten. Beachte die zusätzliche Einspeisung von GND und 5V für die Beiche.
Du hast ja noch nicht konkret ausgedrückt, was Du eigentlich willst.

Gruß Tommy

Danke für den Tipp, ich stöber mich mal durch.

Ich würde gerne sowohl jeden Bereich einzeln als auch den Gesamtstreifen auf einmal ändern können. Beim ganzen Bereich dann vielleicht sogar so, dass man entweder wirklich den gesamten Streifen durchzählen lässt. Also z.B. Regenbogen von Led 1 bis Led 124 oder mit einem Klick alle Bereiche den Befehl geben kann, damit dann in jedem Bereich einzeln der gewünschte Effekt abläuft. Das ganze dann jeweils auch über den "Server" um da die Farben ändern zu können ohne etwas angeschlossen zu haben.

Um den Code nicht ausufern zu lassen wäre vielleicht auch nett ne Variableneinstellung des Leds Counters zu haben. Ich sag jetzt mal z.B. x und y und dann halt per Schleife hochzählen zu lassen. Dann bräuchte man nicht jede Funktion 10x zu machen sondern könnte das dann einfach eingeben und müsste sich nur die Verlinkungen vernüftig ordnen

Ich hab da mal was ähnliches gemacht..

Ohne framework ist das schon ein bisschen Weg.

Vielen Dank :slight_smile:

Bin jetzt soweit, dass ich jeden Block für ne feste Farbe einzeln einstellen kann.
Einzelne Funktionen laufen nicht gleichzeitig, aber mir reicht auch ein Verlauf über die gesamte Lampe.
Programmiermäßig hab ich also die gröbsten Sachen und muss nur mal nach ein paar Funktionen gucken, die vielleicht ganz cool wären. Lauflicht oder auf und abdimmen im Loop und sowas in der Art, aber hatte ich noch keine richtige Zeit für, sollte ich da nicht klar kommen nerv ich euch nochmal ^^

Hey, ich stell mich gerade mal wieder ein bisschen dumm an:

Würde gerne eine Art Lauflicht haben, also so in der Art, dass er zuerst die erste Led anmacht und dann mit und mit die anderen Leds. Sobald er dann am Ende ist dann im Loop wieder von vorne anfängt (oder vielleicht dann in die andere Richtung zurückgeht). Die Farbe würde ich jedoch gerne frei einstellen können (Farbcode wird dann über Html eingegeben)
Der vorher genannte Sketch, den ich nutze hat auch einen Teil mit dem man die Farbe variabel ändern kann:

#include "LedFunction.h"

class SimpleRGBFunction: public LedFunction
{
  public:
    uint8_t rgb[3] = {0, 0, 0};
    bool set = false;

  SimpleRGBFunction()
  {    
  }

  virtual bool init(ESP8266WebServer &server)
  {
    if(!loadRGBValues(server, rgb))
      return false;
  }
  
  virtual void render()
  {
    if(set)
      return;
    for(int i = 0; i < state->count; i++)
      state->setRgb(i, rgb[0], rgb[1], rgb[2]);
    set = true;  
  }
};

Also eigentlich müsste man doch nur unten den Teil mit der for Schleife erweitern oder?

Bei meinen traurigen Versuchen mit if Bedingungen und i++ hats bisher leider nicht wirklich geleuchtet ^^