NEWS
On event/trigger in JavaScript Klasse verwenden
-
Hallo,
ich bin Momentan dabei die JavaSkripte für die Beleuchtung in meinem Heim zu verbessern/überarbeiten.Ich würde gerne eine Klasse für die Beleuchtung anlegen.
Das Skript sieht folgendermaßen aus://room and light names var roomName = "livingRoom" var lightName = "light1" //physical light var stateID = 'zigbee.0.00158d000484f150.state'/*Switch state*///'zigbee.0.group_1.state'/*Switch state*/ var brighnessID = 'zigbee.0.00158d000484f150.brightness'/*Brightness*///'zigbee.0.group_1.brightness'/*Brightness*/ var colortempID = 'zigbee.0.00158d0001aa6b65.colortemp'/*Color temperature*///'zigbee.0.group_1.colortemp'/*Color temperature*/ var rgbcolorID = "" //physical button var buttonClickID = 'shelly.0.SHSW-1#500291F0A6E5#1.Relay0.Input'/*Input / Detach*/ var buttonDoubleClickID = "" var buttonHoldID = "" class light { constructor(roomName, lightName, stateID, brightnessID, colorTempID, RGBcolorID, buttonClickID, buttonDoubleClickID, buttonHoldID) { this.roomName = roomName this.lightName = lightName this.stateID = stateID this.brighnessID = brightnessID this.colorTempID = colorTempID this.RGBcolorID = RGBcolorID this.buttonClickID = buttonClickID this.buttonDoubleClickID = buttonDoubleClickID this.buttonHoldID = buttonHoldID log(this.stateID) //debug //set new folder for the light and objects for state, brightness etc. but only if parameter was given to constructor if(this.stateID != ""){ //create userdata object for virtual light createState(("0_userdata.0." + roomName + "." + this.lightName + ".state"), false, function() { //Init physical light log(this.stateID) //debug log(stateID) //debug log("0_userdata.0." + this.roomName + "." + this.lightName + ".state") //debug log(getState("0_userdata.0.livingRoom.light1.state").val) //debug log(getState("0_userdata.0." + roomName + "." + this.lightName + ".state").val) //debug setState(this.stateID, getState("0_userdata.0." + roomName + "." + this.lightName + ".state").val) }); } if(this.brighnessID != ""){ createState(("0_userdata.0." + this.roomName + "." + this.lightName + ".brightness"), 255, function() { setState(this.brighnessID, getState("0_userdata.0." + roomName + this.lightName + ".brightness").val) }); } if(this.colorTempID != ""){ createState(("0_userdata.0." + this.roomName + "." + this.lightName + ".colorTemp"), 100, function() { setState(this.colorTempID, getState("0_userdata.0." + roomName + "." + this.lightName + ".colorTemp").val) }); } if(this.RGBcolorID != ""){ createState(("0_userdata.0." + this.roomName + "." + this.lightName + ".RGBcolor"), false, function() { setState(this.RGBcolorID, getState("0_userdata.0." + roomName + "." + this.lightName + ".RGBcolor").val) }); } } //turn on/off light setLight(trigger){ if(getState(this.stateID).val){ setState(this.stateID, false); setState("0_userdata.0." + this.roomName + "." + this.lightName + ".state", false, true) log("Light turned off by " + trigger) } else{ setState(this.stateID, true); setState("0_userdata.0." + this.roomName + "." + this.lightName + ".state", true, true) log("Light turned on by " + trigger) } } //Methods for changing brightness, colortemp and rgb //Trigger shelly button click (momentary switch) //on({id: this.buttonClickID, val: true}, function (obj) { //not working //this.setLight("button") //Not working //}) //not working //Trigger button double tap and hold //Trigger from siri over "0_userdata.0.livingRoom.light1.state" } const livingRoomLight = new light(roomName, lightName, stateID, brighnessID, colortempID, rgbcolorID, buttonClickID, buttonDoubleClickID, buttonHoldID);
Es wird ein virtuelles Licht durch createState im Konstruktor angelegt. Je nach Übergabe-Parameter werden neben dem Objekt State auch die Objekte Brightness, ColorTemp und RGB angelegt. Zudem wird das “physische Licht” (in dem Fall Zigbee) initialisiert - state false, brightness 255 etc.
Es wurde testhalber eine Methode angelegt um das Licht erstmal ein/auszuschalten. Die Methode funktioniert, wenn der Trigger ausserhalb der Klasse angelegt wird.
Ich würde gerne nun mehrer Trigger in der Klasse anlegen (ab Zeile 71). Im Regelfall gibt es pro Raum einen Lichtschalter (Shelly/Zigbee) und einen virtuellen Schalter mittels Siri (yahka) welcher die durch createState angelegten Objekte in userdata ändert.
Wie kann ich am besten einen Trigger in der Klasse realisieren? Das obere Beispiel funktioniert jedenfalls nicht und der Output sieht folgendermaßen aus:00:25:50.872 info javascript.0 (2155) Start javascript script.js.living_room.living_room_light_oop 00:25:50.885 info javascript.0 (2155) script.js.living_room.living_room_light_oop: zigbee.0.00158d000484f150.state 00:25:50.886 info javascript.0 (2155) script.js.living_room.living_room_light_oop: registered 0 subscriptions and 0 schedules 00:25:50.962 info javascript.0 (2155) script.js.living_room.living_room_light_oop: undefined 00:25:50.962 info javascript.0 (2155) script.js.living_room.living_room_light_oop: zigbee.0.00158d000484f150.state 00:25:50.963 info javascript.0 (2155) script.js.living_room.living_room_light_oop: 0_userdata.0.undefined.undefined.state 00:25:50.963 info javascript.0 (2155) script.js.living_room.living_room_light_oop: false 00:25:50.964 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:40:21) 00:25:50.964 info javascript.0 (2155) script.js.living_room.living_room_light_oop: null 00:25:50.965 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:41:40) 00:25:50.967 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:41:17) 00:25:50.971 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:46:44) 00:25:50.973 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:46:17) 00:25:50.977 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:51:44) 00:25:50.979 warn javascript.0 (2155) at Object.<anonymous> (script.js.living_room.living_room_light_oop:51:17)
Die Objekte in Userdata werden aber angelegt:
Warum wird this.stateID in Zeile 27 ausgegeben aber in Zeile 33 nicht?
Sollte die Klasse funktionieren, wie kann ich Objekte in neuen (leeren) Skripten anlegen ohne jedes Mal die Klasse kopieren zu müssen?
Mir ist bekannt das man mittels TypeSkript Funktionen auslagern kann.
Muss ich mit der Klasse später auch diesen Weg gehen?Für heute genug IOBroker - ich geh jetzt ins Bett.
Grüße
ChristophDer IOBroker wurde vor ein paar Tagen von 3.x.x auf 4.0.24 geupdatet.
Node.js v12.22.6
NPM 6.14.15Raspberry ist Model 4 mit 4gb RAM
-
@csuser sagte in On event/trigger in JavaScript Klasse verwenden:
Warum wird this.stateID in Zeile 27 ausgegeben aber in Zeile 33 nicht?
irgendwas stimmt mit den zeilennnummern nicht.
weder in 27 noch in 33 gibt es was mit this.stateID
aber ich vermute mal das es sich einmal im callback der createstate funktion befindet und einmal ausserhalb.createstate ist eine async funktion, daher ist this im callback nicht deine klasse, sondern etwas anderes (musst schauen was der callback bereitstellt), daher steht stateID unter this dort nicht zur Verfügung.
um das zu lösen könntest du vor createState den Wert aus this.stateID einer Variable mit let zuweisen oder die createstate funktion an den aktuellen scope binden
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind?retiredLocale=de
allerdings finde ich das persönlich sehr hässlich (obwohl ich es auch schon häufig so eingesetzt habe)hier noch dazu was zum lesen
https://www.pluralsight.com/guides/javascript-callbacks-variable-scope-problem
meine 2. Lösung hat er unter ES6 verzeichnet.
Die bind Lösung steht gar nicht da. Aber bind macht ungefähr sowas wie die Funktion zusammen mit der Variable in eine closure einpacken und die funktion dann verwenden -
@oliverio sagte in On event/trigger in JavaScript Klasse verwenden:
createstate ist eine async funktion, daher ist this im callback nicht deine klasse, sondern etwas anderes (musst schauen was der callback bereitstellt), daher steht stateID unter this dort nicht zur Verfügung.
Genau. Grund ist der Context von
this
. Daher am besten mit Arrow-Functions in den Callbacks arbeiten. -
@csuser
Das Thema ist zwar schon ziemlich alt, weil ich aber selbst vor diesem Problem stand hier die Lösung wie man Trigger in einer Klasse realisiert: Man muss das in eine Methode auslagern (die man aber im constructor ausführen kann)class MyClass{ constructor(){ this.SetUpTrigger(); } SetUpTrigger(){ on("javascript.0.Bla.Blub", function(obj){ console.log(obj.id)}); } } let Class = new MyClass();