Farbtemperatursteuerung von RGBWW Leuchtmitteln

Begonnen von Pythonf, 11 Oktober 2018, 10:45:55

Vorheriges Thema - Nächstes Thema

Pythonf

Hallo FHEM-Freunde,

Ich setze bei mir im Wohnzimmer eine Kombination aus E27 HUE Lampen und RGBWW 4in1 24 V LED-Streifen mit der Firmware aus dem Forum https://github.com/patrickjahns/esp_rgbww_controller ein. Um die Farbtemperatur der LED-Streifen anzupassen habe ich ein cmdalias angelegt, welches sich auf alle Leuchtmittel erweitern lassen kann. Es führt ein least square fitting durch aufgenommene Werte bei vorher definierten Farbtemperaturen durch. Die Einbindung in FHEM gliedert sich in mehrere Schritte:

Zunächst die Aufnahme der optimalen R, G, B, (W) - Werte des jeweiligen Leuchtmittels bei unterschiedlichen Farbtemperaturen (siehe Anhang, Werte von 0 - 1023, geht auch 0 - 255).
Im Anschluss müssen die Werte in die entsprechende cmdalias eingetragen werden, was in meinem Fall wie folgt aussieht:
set RGBW_.* ct .* AS { #Anpassung an die Bennenung der Geräte notwendig

use POSIX;

my @ct = (2000, 3000, 4000, 5000, 6000, 7000, 8000);
my @r_val = (1023, 768, 512, 256, 512, 768, 1023);
my @g_val = (256 ,256 ,256 ,256 ,512 ,768 , 1023);
my @b_val = (0   ,0   ,128 ,256 ,512, 768, 1023);
my @w_val = (768, 1023, 1023, 1023, 1023, 1023, 1023);

my $new_r;
my $new_g;
my $new_b;
my $new_w;

my $new_ct = $EVTPART2;

my @run_var;
my $vars;
my $i;

for($i=0;$i<=3;$i++){
if($i eq 0){@run_var = @r_val};
if($i eq 1){@run_var = @g_val};
if($i eq 2){@run_var = @b_val};
if($i eq 3){@run_var = @w_val};

$vars = lsqf(\@ct, \@run_var);

my $apar = @{ $vars }[0];
my $bpar = @{ $vars }[1];
my $cpar = @{ $vars }[2];

$vars = ceil($apar + $new_ct*$bpar + $new_ct * $new_ct * $cpar);

if($vars > 1023){$vars = 1023};
if($vars < 0){$vars = 0};

if($i eq 0){$new_r = $vars};
if($i eq 1){$new_g = $vars};
if($i eq 2){$new_b = $vars};
if($i eq 3){$new_w = $vars};
}
fhem("set $EVTPART0 raw $new_r,$new_g,$new_b,$new_w"); #Abänderung für das jeweilige Device notwendig
}


Wichtig ist noch, die Funktion  lsqf in der 99_myUtils.pm anzulegen:

use Algorithm::CurveFit;
use JSON;
use POSIX;

sub lsqf { #leastsquarefit
my ($x_ref, $y_ref) = @_;
my @xdata = @{ $x_ref };
my @ydata = @{ $y_ref };

my $formula = 'a + b * x + c * x^2'; #Funktion kann angepasst werden, falls notwendig. Ich würde allerdings abraten
my $variable = 'x';

my @parameters = (
# Name    Guess   Accuracy
['a',     1,    0.01],  # If an iteration introduces smaller
['b',     1,     0.01],  # changes that the accuracy, end.
['c',     1,     0.01],  # changes that the accuracy, end.
);

my $max_iter = 100; # maximum iterations

my $square_residual = Algorithm::CurveFit->curve_fit(
formula            => $formula, # may be a Math::Symbolic tree instead
params             => \@parameters,
variable           => $variable,
xdata              => \@xdata,
ydata              => \@ydata,
maximum_iterations => $max_iter,
);

my @avar = split(/,/, to_json($parameters[0]) );
    my @bvar = split(/,/, to_json($parameters[1]) );
my @cvar = split(/,/, to_json($parameters[2]) );

my @var = (@avar[1], @bvar[1], @cvar[1]);

return \@var ;

}


Eventuell muss noch das Paket "cpan install Algorithm::CurveFit" installiert werden.

Das ganze funktioniert mit einer flexiblen Anzahl von Messwerten und sollte sich mit wenig Aufwand auf andere Geräte übertragen lassen.
Zu Testzwecken habe ich noch ein perl-Skript, mit dem die Kalibrationswerte getestet werden können angehängt (fit.pl).

Da ich nur in meiner Freizeit programmiere bin ich mir sicher, dass an meinem Code noch Dinge sind, welche sich aufhübschen lassen und ich würde mich freuen, vorgeschlagene Änderungen auch einzubauen.

Bei Fragen steh ich natürlich gerne zur Verfügung. Die Farbwiedergabe kann hierbei m.M. nach gut mit den HUE Leuchtmittel mithalten bzw. gefällt mir teilweise sogar besser.

Fabian

Pythonf

Bei mir funktioniert seit dem Umstieg auf Ubuntu 18.04 LTS das Paket CurveFit leider nicht mehr.
Deshalb habe ich eine kleine Änderung durchgeführt, die das manuelle Berechnen und Einfügen der Werte erlaubt und auf die 99_myUtils.pm vollständig verzichtet.
Hierzu einfach in Excel, Qtiplot, etc.. einen Polynomial Fit beliebigen Grades durch die Werte für jede LED durchführen und dir Parameter
a0,a1,..., an   aus dem Polynom (a0 + a1×ct + a2×ct2 + ... + an×ctn)
in dieser Reihenfolge durch Kommata getrennt in die jeweiligen Arrays eintragen.
set RGBW_.* ct .* AS {

use POSIX;

my @r_par = (2228.0714285714, -0.7302380952381, 7.302380952381e-05);
my @g_par = (602.57142857143, -0.23722619047619, 3.6511904761905e-05);
my @b_par = (35.714285714286, -0.080273809523809, 2.5845238095238e-05);
my @w_par = (531.21428571428, 0.17910714285714, -1.5178571428571e-05);

my $new_ct = $EVTPART2;

my $new_r;
my $new_g;
my $new_b;
my $new_w;

my @par;
for(my $i=0;$i<=3;$i++){
if($i eq 0){@par = @r_par};
if($i eq 1){@par = @g_par};
if($i eq 2){@par = @b_par};
if($i eq 3){@par = @w_par};
my $vars = 0;
for(my $k=0; $k < (scalar @par); $k++){
$vars = ceil($vars + @par[$k]*($new_ct**$k));
}

if($vars > 1023){$vars = 1023};
if($vars < 0){$vars = 0};

if($i eq 0){$new_r = $vars};
if($i eq 1){$new_g = $vars};
if($i eq 2){$new_b = $vars};
if($i eq 3){$new_w = $vars};
}
fhem("set $EVTPART0 raw $new_r,$new_g,$new_b,$new_w");
}


Das ganze liefert sehr schöne Farbtemperaturübergänge. Bei Fragen helfe ich gerne weiter.

Fabian