Ambilight

Aus EasyVDR Wiki
Wechseln zu: Navigation, Suche
Ambilight neu.jpg

Vorwort:

Dieses Thema bezieht sich auf einzelne Varianten, die bei der Umsetzung eines Nachbau von Usern gesammelt wurden.

Variante Arduino mit WS2801 oder APA102C LED-Stripe:

Hardware

Arduino Nano ATmega328 mit FTDI Chip

WS2801 5050 RGB LED strip 32 LEDs/m

APA102C 5050 RGB LED strip 60 LEDs/m

5V 7-16A Netzteil

Hier variiert die Ampere an der Anzahl der LEDs.

Bei einer Anzahl von über 100LEDs empfiehlt es sich ein Netzteil mit mehr als 10A zu nehmen.

Hinweis: Jeder ist selbst für seine Sicherheit verantwortlich. Den Strom bitte messen und das Netzteil passend zur maximalen Helligkeit+10% Sicherheitszuschlag auswählen. Auch und gerade bei der niederen Spannung können durch Fehler Brände ausgelöst werden

Aufbau

Ambilight Aufbau.jpg

Beim Strips verlegen unbedingt darauf achten, neben dem WS2801 Chip ist ein kleiner weißer Pfeil für die Verlege-Richtung aufgedruckt. Wird einer der Strips falschen rum eingebunden, passiert ab dem Anschluss nichts.

Ab einer Länge von 2m, sollte unbedingt eine weitere Einspeisung durch das Netzteil erfolgen.

Der Arduino benötigt nur einen gemeinsamen GND vom Netzteil, eine 5V Einspeisung ist nicht nötig, da durch USB versorgt.

In diesem Beispiel (Sketch weiter unten), werden die Stripes mit CK > D13, SI > D6 an den Arduino angeschlossen.

Unterschiedliche Beispiele/Varianten der Rahmen:

Hier wäre es möglich, den Abstrahlwinkel der LEDs individuell einzustellen.

( Beispiel: Sollte der TV mal aus Zufall wachsen, muss nicht gleich ein größerer Rahmen her )

Dazu benötigt man lediglich noch ein Kunststoffrohr, oder Alurohr auf dem Rahmengerüst.

Minimal knifflig, da an den jeweiligen stellen der Verbindungen das Rohr ausgeklinkt werden muss.

Zusätzlich sollte man die Aluleisten mit Isolierband an 3 Stellen pro Schiene umkleben, damit das Rohr nicht zu lose auf dem Rahmen steckt.


In diesem Beispiel wurden hier die LEDs direkt auf Rahmen plaziert

Software

Hier empfiehlt es sich zuerst den x Desktop auf LXDE zu wechseln. Bei openbox ist die USB Unterstützung nicht vollständig ausgebaut, daher kann unter Umständen der Arduino nicht gefunden werden.


-Arduino IDE ( <- Die kostenlose Programmiersoftware )

Getestet wurde bisher mit Arduino IDE Version 1.8.1. & 1.8.5 auf Linux & Windows 10

In der Menüleiste, sollte unter "Werkzeuge > Board" als erstes unser Arduino ausgewählt werden. In unserem Fall "Arduino Nano"

Dann bei "Werkzeuge > Prozessor" ATmega328 und zum Schluss "Werkzeuge > Port" /etc/ttyUSBx ( wahlweise, wo der Arduino am USB hängt )

Sollte die Software folgende Meldung anzeigen:

Arduino Aktualisierung.png

Empfiehlt es sich, diese Aktualisierung durchzuführen, andernfalls könnten wichtige Bibliotheken für die Programmierung fehlen.

Über den Bibliotheksmanger (Sketch/Bibiliothek einbinden/ Bibliotheken verwalten) die Bibliotheken aus den "Includes" einbinden.
ArduinoBibliothek.png
In unserem Fall also die FastLED Bibliothek damit die zum Kompilieren geforderte FastLED.h verfügbar ist.

Ist der Sketch geladen und passend zur Hardware angepasst, muss dieser nun nur noch unter Menüleiste "Sketch > Hochladen" aufgespielt werden.


Hinweis: Sollten wir Hyperion, oder einen anderen Dienst welcher auf die USB Schnittstelle zugreift im Vorfeld installiert haben, muss dieser Dienst vor dem aufspielen gestoppt werden. Bei Hyperionsudo stop hyperion


-Arduino Sketch ( Software, die mit Arduino IDE auf den Arduino gespielt wird )

Wahlweise kann hier auch der LED-Typ bei Verwendung von Beispielsweise APA102 individuell angepasst werden, in diesem Fall #define LED_TYPE WS2801 ändern in #define LED_TYPE APA102

Es sollte unbedingt die Anzahl der LED's #define MAX_LEDS 410 angepasst werden. Hier bitte darauf achten, Anzahl der LED's + 1. Haben wir also 128 LED's, sieht der Eintrag wie flogt aus #define MAX_LEDS 129

Die Baudrate ist hier schon auf den maximalen Wert eingestellt ( 500000 )#define serialRate 500000 und muß später in Hyperion eingetragen werden.

Programmcode(Adalight) hier drunter einfach in das geöffnete Arduino IDE Programm einfügen.

#include "FastLED.h"

#define ANALOG_MODE_AVERAGE  0
#define ANALOG_MODE_LAST_LED 1

/**************************************
   S E T U P

   set following values to your needs
 **************************************/

#define INITIAL_LED_TEST_ENABLED true
#define INITIAL_LED_TEST_BRIGHTNESS 32  // 0..255

// Number of leds in your strip. set to "1" and ANALOG_OUTPUT_ENABLED to "true" to activate analog only
// As of 26/1/2017:
// 582 leaves ZERO bytes free and this
// 410 is ok
// tested with 500 leds and is fine (despite the warning)
#define MAX_LEDS 410

// type of your led controller, possible values, see below
#define LED_TYPE WS2801 

// 3 wire (pwm): NEOPIXEL BTM1829 TM1812 TM1809 TM1804 TM1803 UCS1903 UCS1903B UCS1904 UCS2903 WS2812 WS2852
//               S2812B SK6812 SK6822 APA106 PL9823 WS2811 WS2813 APA104 WS2811_40 GW6205 GW6205_40 LPD1886 LPD1886_8BIT 
// 4 wire (spi): LPD8806 WS2801 WS2803 SM16716 P9813 APA102 SK9822 DOTSTAR

// For 3 wire led stripes line Neopixel/Ws2812, which have a data line, ground, and power, you just need to define DATA_PIN.
// For led chipsets that are SPI based (four wires - data, clock, ground, and power), both defines DATA_PIN and CLOCK_PIN are needed

// DATA_PIN, or DATA_PIN, CLOCK_PIN
// #define LED_PINS 6        // 3 wire leds
#define LED_PINS 6, 13  // 4 wire leds

#define COLOR_ORDER GRB  // colororder of the stripe, set RGB in hyperion

#define OFF_TIMEOUT 15000    // ms to switch off after no data was received, set 0 to deactivate

// analog rgb uni color led stripe - using of hyperion smoothing is recommended
// ATTENTION  this pin config is default for atmega328 based arduinos, others might work to
//            if you have flickering analog leds this might be caused by unsynced pwm signals
//            try other pins is more or less the only thing that helps
#define ANALOG_OUTPUT_ENABLED false
#define ANALOG_MODE           ANALOG_MODE_LAST_LED  // use ANALOG_MODE_AVERAGE or ANALOG_MODE_LAST_LED
#define ANALOG_GROUND_PIN     8                     // additional ground pin to make wiring a bit easier
#define ANALOG_RED_PIN        9
#define ANALOG_GREEN_PIN      10
#define ANALOG_BLUE_PIN       11

// overall color adjustments
#define ANALOG_BRIGHTNESS_RED   255              // maximum brightness for analog 0-255
#define ANALOG_BRIGHTNESS_GREEN 255              // maximum brightness for analog 0-255
#define ANALOG_BRIGHTNESS_BLUE  255              // maximum brightness for analog 0-255

#define BRIGHTNESS 255                      // maximum brightness 0-255
#define DITHER_MODE BINARY_DITHER           // BINARY_DITHER or DISABLE_DITHER
#define COLOR_TEMPERATURE CRGB(255,255,255) // RGB value describing the color temperature
#define COLOR_CORRECTION  TypicalLEDStrip   // predefined fastled color correction
//#define COLOR_CORRECTION  CRGB(255,255,255) // or RGB value describing the color correction

// Baudrate, higher rate allows faster refresh rate and more LEDs
//#define serialRate 460800      // use 115200 for ftdi based boards
//#define serialRate 115200      // use 115200 for ftdi based boards
#define serialRate 500000         // use 115200 for ftdi based boards


/**************************************
   A D A L I G H T   C O D E

   no user changes needed
 **************************************/

// Adalight sends a "Magic Word" (defined in /etc/boblight.conf) before sending the pixel data
uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i;

unsigned long endTime;

// Define the array of leds
CRGB leds[MAX_LEDS];

// set rgb to analog led stripe
void showAnalogRGB(const CRGB& led) {
  if (ANALOG_OUTPUT_ENABLED) {
    byte r = map(led.r, 0,255,0,ANALOG_BRIGHTNESS_RED);
    byte g = map(led.g, 0,255,0,ANALOG_BRIGHTNESS_GREEN);
    byte b = map(led.b, 0,255,0,ANALOG_BRIGHTNESS_BLUE);
    analogWrite(ANALOG_RED_PIN  , r);
    analogWrite(ANALOG_GREEN_PIN, g);
    analogWrite(ANALOG_BLUE_PIN , b);
  }
}

// set color to all leds
void showColor(const CRGB& led) {
  #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
  LEDS.showColor(led);
  #endif
  showAnalogRGB(led);
}

// switch of digital and analog leds
void switchOff() {
  #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
  memset(leds, 0, MAX_LEDS * sizeof(struct CRGB));
  FastLED.show();
  #endif
  showAnalogRGB(leds[0]);
}

// function to check if serial data is available
// if timeout occured leds switch of, if configured
bool checkIncommingData() {
  boolean dataAvailable = true;
  while (!Serial.available()) {
    if ( OFF_TIMEOUT > 0 && endTime < millis()) {
      switchOff();
      dataAvailable = false;
      endTime = millis() + OFF_TIMEOUT;
    }
  }

  return dataAvailable;
}

// main function that setups and runs the code
void setup() {
  Serial.begin(serialRate);

  // analog output
  if (ANALOG_OUTPUT_ENABLED) {
    // additional ground pin to make wiring a bit easier
    pinMode(ANALOG_GROUND_PIN, OUTPUT);
    digitalWrite(ANALOG_GROUND_PIN, LOW);
    pinMode(ANALOG_BLUE_PIN , OUTPUT);
    pinMode(ANALOG_RED_PIN  , OUTPUT);
    pinMode(ANALOG_GREEN_PIN, OUTPUT);
  }

  // Uncomment/edit one of the following lines for your leds arrangement.
  int ledCount = MAX_LEDS;
  if (ANALOG_MODE == ANALOG_MODE_LAST_LED) {
    ledCount--;
  }

  #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
    FastLED.addLeds<LED_TYPE, LED_PINS, COLOR_ORDER>(leds, ledCount);
  #endif
  
  // color adjustments
  FastLED.setBrightness ( BRIGHTNESS );
  FastLED.setTemperature( COLOR_TEMPERATURE );
  FastLED.setCorrection ( COLOR_CORRECTION );
  FastLED.setDither     ( DITHER_MODE );

  // initial RGB flash
  #if INITIAL_LED_TEST_ENABLED == true
  Serial.println("initial test");
  showColor(CRGB(INITIAL_LED_TEST_BRIGHTNESS, 0, 0));  delay(400);
  showColor(CRGB(0, INITIAL_LED_TEST_BRIGHTNESS, 0));  delay(400);
  showColor(CRGB(0, 0, INITIAL_LED_TEST_BRIGHTNESS ));  delay(400);
  #endif
  showColor(CRGB(0, 0, 0));

  Serial.print("Ada\n"); // Send "Magic Word" string to host


  boolean transmissionSuccess;
  unsigned long sum_r, sum_g, sum_b;

  // loop() is avoided as even that small bit of function overhead
  // has a measurable impact on this code's overall throughput.
  for(;;) {
    // wait for first byte of Magic Word
    for (i = 0; i < sizeof prefix; ++i) {
      // If next byte is not in Magic Word, the start over
      if (!checkIncommingData() || prefix[i] != Serial.read()) {
        i = 0;
      }
    }

    // Hi, Lo, Checksum
    if (!checkIncommingData()) continue;
    hi = Serial.read();
    if (!checkIncommingData()) continue;
    lo = Serial.read();
    if (!checkIncommingData()) continue;
    chk = Serial.read();

    // if checksum does not match go back to wait
    if (chk != (hi ^ lo ^ 0x55)) continue;

    memset(leds, 0, MAX_LEDS * sizeof(struct CRGB));
    transmissionSuccess = true;
    sum_r = 0;
    sum_g = 0;
    sum_b = 0;

    int num_leds = min ( MAX_LEDS, (hi<<8) + lo + 1 );

    // read the transmission data and set LED values
    for (int idx = 0; idx < num_leds; idx++) {
      byte r, g, b;
      if (!checkIncommingData()) {
        transmissionSuccess = false;
        break;
      }
      r = Serial.read();
      if (!checkIncommingData()) {
        transmissionSuccess = false;
        break;
      }
      g = Serial.read();
      if (!checkIncommingData()) {
        transmissionSuccess = false;
        break;
      }
      b = Serial.read();
      leds[idx].r = r;
      leds[idx].g = g;
      leds[idx].b = b;
      #if ANALOG_OUTPUT_ENABLED == true && ANALOG_MODE == ANALOG_MODE_AVERAGE
          sum_r += r;
          sum_g += g;
          sum_b += b;
      #endif
    }

    // shows new values
    if (transmissionSuccess) {
      endTime = millis() + OFF_TIMEOUT;
      #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
      FastLED.show();
      #endif

      #if ANALOG_OUTPUT_ENABLED == true
        #if ANALOG_MODE == ANALOG_MODE_LAST_LED
          showAnalogRGB(leds[MAX_LEDS-1]);
        #else
          showAnalogRGB(CRGB(sum_r/MAX_LEDS, sum_g/MAX_LEDS, sum_b/MAX_LEDS));
         #endif
      #endif
    }
  }
} // end of setup

void loop() {
  // Not used. See note in setup() function.
}

-Hyperion NG

Installation:

Als erstes benötigen wir wichtige Dateien, das unser Build sauber durchläuft:

sudo apt-get update
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev

Jetzt holen wir uns die Repository und upgraden unser System:

sudo add-apt-repository ppa:george-edison55/cmake-3.x
sudo apt-get update && sudo apt-get upgrade

Build holen/compilieren/installieren Manuelle Variante:

git clone --recursive https://github.com/hyperion-project/hyperion.ng.git hyperion
cd hyperion
mkdir build
cd build
cmake -DPLATFORM=x86-dev -DCMAKE_BUILD_TYPE=Release ..
make -j $(nproc)
sudo make install/strip

Jetzt müssen wir noch den Start von HyperionNG automatisieren, daher habe ich folgendes Skript vorbereitet:

Startskript für HyperionNG Daemon(Hyperion Start/Stop Daemon)

Hier empfiehlt es sich zB im x Desktop den xterminal zu nehmen.

Anmelden als easyvdr

su easyvdr

Skripte am besten als Root erstellen

sudo su

Gedit starten

gedit&

und folgendes Skript hier drunter in Gedit einzufügen.

Danach unter /etc/init.d mit Namen HYPERIONd abspeichern.

#! /bin/sh
### BEGIN INIT INFO
# Provides:          Hyperion NG Start
# Required-Start:    Xorg
# Required-Stop:     none
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Hyperion NG Ambiligt
# Description:       Daemon für Hyperion NG /usr/local/lib/hyperiond
### END INIT INFO

#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON="/usr/local/bin/hyperiond"
NAME="HYPERIONd"
DESC="HYPERIONd"
SCRIPTNAME=/etc/init.d/$NAME

DAEMON_OPTS="--rootPath /etc/hyperion hyperionNG.config.json"

. /lib/init/vars.sh
. /lib/lsb/init-functions
. /usr/lib/vdr/easyvdr-config-loader
. /usr/lib/vdr/functions/easyvdr-functions-lib

test -x $DAEMON || exit 0

start_hyperiond () {
 while !( check_x_running ) >/dev/null 2>&1 ;do
  sleep 1
 done
 sleep 10
 DISPLAY=$FRONTEND_DISPLAY start-stop-daemon --start --quiet --background \
        --exec  $DAEMON -- $DAEMON_OPTS
 echo "while (pidof Xorg);do sleep 10;done;/etc/init.d/HYPERIONd start" | at now
}

stop_hyperiond () {
    start-stop-daemon --stop --oknodo --quiet --exec $DAEMON
}

set -e

case "$1" in
  start)
    echo -n "Starting $DESC: "
    start_hyperiond;
    echo "$NAME."
    ;;
  stop)
    echo -n "Stopping $DESC: "
    stop_hyperiond;
    echo "$NAME."
    ;;
  restart|force-reload)
    echo -n "Restarting $DESC: "
    stop_hyperiond
    sleep 2
    start_hyperiond
    echo "$NAME."
    ;;
  status)
    start-stop-daemon --status --exec $DAEMON
    echo "$NAME."
    ;;
  *)
    N=/etc/init.d/$NAME
    # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
    echo "Usage: $N {start|stop|status|restart|force-reload}" >&2
    exit 1
    ;;
esac

exit 0

Nach dem erstellen des Daemons, müssen wir ihn noch ausführbar machen:

chmod 777 /etc/init.d/HYPERIONd

Als Abschluss zum Upstart hinzufügen:

sudo update-rc.d HYPERIONd defaults 80 10

Jetzt richten wir uns noch einen Ordner für die JSON config Files ein. Ich habe dafür im Daemon /etc/hyperion vorgegeben.

mkdir /etc/hyperion

Bei Intelgrafik wären wir mit der Installation fertig und können an die Konfiguration von HyperionNG gehen, bei NVidia fehlt noch was, aber dazu später..


Erster Start HyperionNG

/etc/init.d/HYPERIONd start


Konfiguration:

Wir öffnen jetzt einen Internetbrowser im Netzwerk, oder lokal auf dem easyVDR. Sind wir direkt am easyVDR geben wir folgendes in der http Zeile ein:

http://localhost:8090/

Im Netzwerk:

http://<hier die IP-Adresse des easyVDR>:8090/

Nun öffnet sich die Konfigurationsseite von HyperionNG. Um alle Einstellungen machen zu können, muss oben rechts auf den Schlüssel gegangen werden und die Einstellungsstufe auf Experte geändert werden. Hier geben wir folgende Werte ein, wenn wir einen Arduino Nano mit WS2801Led's und dem Sketch aus dem easyVDR-Wiki haben.

In der "Konfiguration" > "LED Hardware" folgendes eingestellen

> Steuerungstyp = Adalight

> RGB Typ Reihenfolge = BRG

> Aktualisierungszeit = 100

> Ausgabepfad = /dev/ttyUSB0 < hier solltet ihr schauen, wo euer Arduino am System hängt

> Baudrate = 500000

> Verzögerung nach Verbindung = 0

Nachdem wir "Einstellungen speichern" und darauf "Hyperion neu starten" gedrückt haben, sollten einige LED's schon anfangen zu leuchten.


In der nächsten Option "LED Layout" können wir nun die Anzahl der LED's oben/unten/links/rechts Einspeisepunkt und die Richtung, wie wir verkabelt haben einstellen.


Dann muss noch die Aufnahmehardware angepasst werden

In der "Konfiguration" > "Aufnahme Hardware"

> Typ = x11

> Aufnahmefrequenz = 60

> Priorität = 250


Das Wichtigste ( zumindest bei VAAPI bzw Intel ) wären dann bei Bildverarbeitung > Glättung

In der "Konfiguration" > "Bildverarbeitung" > "Glättung"

> Art = Linear

> Zeit = 25 <<< Sollte das Ambilight zu hektisch wechseln, kann man das mit diesem Punkt gut abfangen, um so höher der Wert, desto ruhiger wird's

> Aktualisierungsfrequenz = 25 <<< Damit habe ich das Flimmer und Flackern bei unterschiedlichen Bildwiedergaben vollständig in den Griff bekommen.

> Aktualisierungsverzögerung = 2 <<< Im VDR ist die Aktualisierung eventuell schneller und im Kodi bei zB Onlinestreams minimal langsamer, daher liegt man mit 2ms recht gut im Mittelfeld


Ab hier nur für NVIDIA

Hier benötigen wir noch den angebotenen Boblight Server im Hyperion

In der "Konfiguration" > "Netzwerk" > "Boblight Server" > "Aktiviert" auswählen


Nun benötigen wir noch für den VDR das boblight Plugin

sudo stopvdr
sudo apt-get install vdr-plugin-boblight
sudo startvdr

Das Plugin muss im VDR noch aktiviert werden und der VDR benötigt einen Restart um die Aktivierung zu übernehmen.


Jetzt modifizieren den Program-Changer, dazu muss unter /usr/share/easyvdr/program-changer/lib/ die Datei show-hide-menu.sh editiert werden und mit folgenden Eintrag ergänzt werden:

HINWEIS Bitte vollständigen Inhalt durch folgenden ersetzen

#!/bin/bash
##### Beim Drücken der Taste SHOW_HIDE_MENU wird dieses Skript gestartet
############ Skript zum abschalten der Fernbedienung des VDR ###########
####################### Version 0.4  21.06.2012 ########################
# Version 0.5  10.07.12 Bleifuss2 Mute Parameter hinzugefügt
#              14.05.14 Mute entfernt
#              17.10.15 Anpassungen für Kodi
#Anderungen an der Variable müssen im Skript program-changer.sh & start_program.sh ebenfalls durchgeführt werden


TMP_FILE_SHOW_PCHANGER=/tmp/.show_program-changer

DEBUG=0

if [ $DEBUG -eq 1 ]; then
  echo "Parameter: $1 $2 $3 " >> /tmp/program-changer-show-hide-menu.sh
fi


function error {
 svdrpsend   MESG "show-hide-menu.sh Parameter falsch fuer Hilfe show-hide-menu.sh im terminal starten"
 echo 
 echo 
 echo Falscher Parameter
 echo Das Skript schaltet die Fernbedienung des VDR beim Aufruf des Menü aus und beim beenden wieder ein.
 echo Es muss als Parameter -menu-start oder -menu-end übergeben werden.
# echo Syntax: 
 exit 1
}


#Parameter testen
if [ $# -ne 0 ]; then
 if [ $1 = "-menu-start" ]; then
  svdrpsend remo off
  svdrpsend plug vdrboblight mode detach
  chvt 7
#  sleep 0.1
#  svdrpsend  MESG "Fernbedienung im VDR ist jetzt deaktiviert"
 else
  if [ $1 = "-menu-end" ]; then
    #Datei löschen (Befehl für Pchanger anzeigen)
    if [ -e $TMP_FILE_SHOW_PCHANGER ]; then
     rm $TMP_FILE_SHOW_PCHANGER
    fi
    #Nur bei den VDR Frontend die Fernbedienung wieder einschalten
    pgrep easyvdr-runfront*
    if [ $? -eq 0 ]; then
     #Testen ob kodi als Frontend läuft
     pgrep kodi*
     if [ $? -eq 0 ]; then
     exit 0
     fi
#    sleep 0.1
     svdrpsend remo on
     svdrpsend plug vdrboblight mode atmo
     sleep 0.3
#    svdrpsend  MESG "Fernbedienung im VDR ist jetzt Aktiviert"
     exit 0
    fi
  else
   error
  fi
 fi
else
 error
fi

Zum Schluss muss noch der Program-Changer auf hold gesetzt werden, um nicht bei Updates die eben gemachten Einträge zu verlieren.

apt-mark hold easyvdr-addon-program-changer


Fazit: Sollten Probleme/Fragen bei diesen Tread auftreten, bitte in unserem Forum einen gesonderten Post erstellen.