NEWS
Konstantes Dimmen bei gedrückter Taste
-
Hallo zusammen!
Ich bin hier leider nicht wirklich fündig geworden und benötige Hilfe bei der Programmierung einer kontinuierlichen Dimmfunktion solange eine Taste gedrückt bleibt. D.h. ich möchte gerne bei gedrückter Taste von 0 bis 100 variabel Dimmen können. Hierfür habe ich mir die Tradfri Dimmer gekauft, welche die Zustände 1001 (Aus, Taste wird gehalten), 1002 (Aus, Taste gedrückt), 1003 (Aus, Taste nach 1001 losgelassen), sowie das Pendent abgebildet auf 200X.
Geplant war eigentlich das ganze in einem Switch/If-Statement den Tastenzustand abzufragen und über eine While-Schleife das ganze so lange laufen zu lassen bis entweder 100% bzw. 0% erreicht sind oder die Taste vorher losgelassen wird. Hierfür habe ich mir eine Funktion geschrieben, die das theoretisch können sollte.
function setLevel(SwitchState){ if(SwitchState == 1001){ while(Level_Value <= 100){ Level_Value = getState("deconz.0.Lights.1.level").val + 1; console.log(Level_Value); setState("deconz.0.Lights.1.level", Level_Value); } } else{ return; } }
Die Funktion wird auch aufgerufen, jedoch ändert sich die Lichtintensität nicht. Lege ich das was innerhalb der While-Schleife liegt außerhalb hin, so wird der Wert um 1% erhöht. Das ganze stellt hier nur ein Example dar, da ich erst die Grundfunktionalität zum laufen kriegen will. Die Abfrage ob die Taste losgelassen wurde fehlt hier. Hat hier jemand einen Tipp woran es liegt? Besten Dank!
Viele Grüße
Keromida -
@keromida Bei mir in etwa so:
const s01Button1HoldId = oppleSwitch02 + '.' + 'button_'+ n +'_hold'; const s01DimUp_buttonId = s01Button1HoldId; on({id: s01Button1HoldId , change: "gt"}, function(obj){ dimUp_Button() });
async function dimUp_Button() { // dim up if(debugLogOn) console.log('button dim up press '); // clearAllTimouts(); bright = getState(lampBrightnessId ).val; lastLampBright = bright; let buttonHold = getState(s01DimUp_buttonId).val || getState(s02DimUp_buttonId).val; await delay (0.1); while((buttonHold) && (bright < maxBright)){ if(debugLogOn) console.log('loop'); bright = bright + deltaBright ; if (bright >= maxBright) bright = maxBright; //clipping if(debugLogOn) console.log ('bright ' + bright); setState(lampBrightnessId ,bright); lastLampBright = bright; buttonHold = getState(s01DimUp_buttonId).val || getState(s02DimUp_buttonId).val; await delay (0.2); } };
Ikea Floalt als Panel; aqare Opple als Taster (2 Stck, s01 und s02) und ein CC2652P als Koordinator. Kein ikea GW.
Im Übrigen gehen in dieser Konfiguration auch die ikea symfonisk Drehsteller recht gut. Bei Gruppen etwas schlechter
-
@keromida sagte: über eine While-Schleife das ganze so lange laufen zu lassen bis entweder 100% bzw. 0% erreicht sind oder die Taste vorher losgelassen wird.
Verwende ein Intervall, das beim langen Drücken gestartet und beim Loslassen gestoppt wird. Beispiel:
const idLevel = 'deconz.0.Lights.1.level'; const idHeller = '...'; const idDunkler = '...'; var timer = null; function dimmen(delta) { let level = getState(idLevel).val; if(delta > 0 && level < 100 || delta < 0 && level > 0) { timer = setInterval(function() { level += delta; setState(idLevel, level); if(level <= 0 || level >= 100) clearInterval(timer); }, 250); } } on(idHeller, function(dp) { if(dp.state.val == 1001) dimmen(1); else if(dp.state.val == 1003) clearInterval(timer); }); on(idDunkler, function(dp) { if(dp.state.val == 1001) dimmen(-1); else if(dp.state.val == 1003) clearInterval(timer); });
-
@paul53 sagte in Konstantes Dimmen bei gedrückter Taste:
@keromida sagte: über eine While-Schleife das ganze so lange laufen zu lassen bis entweder 100% bzw. 0% erreicht sind oder die Taste vorher losgelassen wird.
Verwende ein Intervall, das beim langen Drücken gestartet und beim Loslassen gestoppt wird.
sollte man dazwischen evtl eine pause einbauen?
die while schleife ist blitzeschnelle bei 100, so das man in real wahrscheinlich kein dimmen wahrnimmt, sondern das licht zack bei 100% ist.bei @klassisch sehe ich so ein delay
-
@oliverio sagte: sollte man dazwischen evtl eine pause einbauen?
Das Intervall macht diese Pause.
-
Danke für eure Antworten! Mein Fehler war tatsächlich schlicht und ergreifend, dass ich keinen Delay gesetzt habe für die Übertragung der Telegramme. Dadurch wurde der Übergang nicht gesetzt. Danke für die Hilfe! Hier der vollständige Code.
/* The code makes the use of the IKEA tradfri dimmer switch to adjust a group of lights over a data point or just a single lamp. */ const id_ButtonEvent = 'deconz.0.Sensors.4.buttonevent'; // Input Button Event Data Point const id_LampBrightnessLevel = 'deconz.0.Lights.1.level'; // Input Level Data Point const id_LampOnState = 'deconz.0.Lights.1.on'; // Input OnState Data Point const max_Brightness = 100; // refers to 100% const min_Brightness = 0; // Refers to 0% const delta_Brightness = 5; // in percent const setBrightnessValue_Delay = 250; // in miliseconds, sets the periodic adjustment of the brightness level let setBrightnessValue = null; function setLampStates(delta_BrightnessValue){ let Level_Value = getState(id_LampBrightnessLevel).val; if((delta_BrightnessValue >= min_Brightness && Level_Value <= max_Brightness) || (delta_BrightnessValue <= 0 && Level_Value >= 0)) { setBrightnessValue = setInterval(function() { Level_Value = Level_Value + delta_BrightnessValue; setState(id_LampBrightnessLevel, Level_Value); if(Level_Value <= 0 || Level_Value >= 100){ clearInterval(setBrightnessValue); } }, setBrightnessValue_Delay); } } on({id: id_ButtonEvent}, async function(obj){ switch(getState(id_ButtonEvent).val){ case 1001:{ setLampStates(delta_Brightness); break; } case 1002:{ setState(id_LampOnState, true); break; } case 1003:{ clearInterval(setBrightnessValue); break; } case 2001:{ setLampStates(-delta_Brightness); break; } case 2002:{ setState(id_LampOnState, false); break; } case 2003:{ clearInterval(setBrightnessValue); break; } } });
-
@keromida sagte in Konstantes Dimmen bei gedrückter Taste:
Die Funktion wird auch aufgerufen, jedoch ändert sich die Lichtintensität nicht. Lege ich das was innerhalb der While-Schleife liegt außerhalb hin, so wird der Wert um 1% erhöht. Das ganze stellt hier nur ein Example dar, da ich erst die Grundfunktionalität zum laufen kriegen will.
Diese Art von schleifen funktionieren prinzipiell nicht.
Grund dafür ist das der ioBroker asynchron arbeitet. Einige Funktionen (in deinem Beispiel die "setState") Funktion kehren zurück bevor die eigentliche Aktion ausgeführt ist. Das Ausführen kann dann noch wenige ms dauern (manchmal auch wenige 10 ms).
Dadurch wird in deiner While Schleifer der Helligkeitswert wahrscheinlich nie erhöht werden. Du kannst zur Vereinfachung davon ausgehen das
- der Befehl setState in Umgangssprache als Merke den Folgenden Wert zur Änderung auf den angegebenen Wert vor ausgedrückt werden kann
- das diese vorgemerkte Änderung effektiv erst passiert wenn Dein Skript abgearbeitet (oder angehalten) ist (z.bsp via den "Pause" Block
- das While/for/repeat schleifen in < 1 ms durchlaufen können.
Wenn Du diesen Annahmen Folgst sollte klar sein das letztendlich der Wert
Level_Value
nie übergetState("deconz.0.Lights.1.level").val + 1
hinaus kommt.Die "best practice" Methode für diese Art Aufgaben hat @paul53 bereits vorgestellt, da gibt es wenig zu ergänzen. Sie ist auch einem Konstrukt mit
While (a) { do something pause(250); }
vorzuziehen.
Du wirst auf Dauer nicht darum herum kommen dich mit timeout und intervall auseinander zu setzen. Die Klassischen "while" schleifen sind für komplexe Aufgaben oft nicht flexibel genug und verleiten dazu zyklisch irgendwelche Werte abzufragen um eine Abbruchbedingung zu bekommen an Statt diese Aufgabe dem ioBroker zu überlassen und die Aktion über einen Trigger zu beenden.
A.
-
@asgothian Danke für die sehr ausführliche und verständliche Antwort! Das bringt jetzt auch eindeutig Licht ins Dunkel wieso mein Code nicht geklappt hat.