theobald Geschrieben September 21, 2020 at 05:54 Geschrieben September 21, 2020 at 05:54 Guten Morgen in die Runde! ich möchte die Daten aus dem Enumeration Callback (Javascript im Browser) in ein Array schreiben (was recht einfach ist). Allerdings kann ich das Array nicht weiter verwenden, da es asynchron erstellt wird. Während nun mein Hauptprogramm in Javascript (im Browser via WebSockets) weiter läuft und im nächsten Aufruf das Array (z.B. var devices = []) lesen will, so hat ipcon.enumerate() das Array aber noch nicht gefüllt, weil es nebenläufig ist. Das ist kniffliger, als ich dachte. Kann mir da jmd. einen Tipp geben? Was habe ich versucht - oder besser angedacht und verworfen? 1. ipcon.on(Enumerate... in ein Promise zu verlagern. Das scheint mir nicht sinnvoll, da es ja nur den Callback deklariert und nicht ausführt. 2. ipcon.enumerate() in ein Promise zu verlagern ->funktioniert aber nicht. 3. ipcon.enumerate() mit async await aufzurufen ->funktioniert auch nicht, da ipcon.enumerate() für jedes device (Brick, Bricklet etc.) erneut aufgerufen wird. Wie müsste ein robuster Ansatz lauten, um die Daten in Enumerate in ein Array zu schreiben und für die Laufzeit des Programms verfügbar zu machen. Das Array soll erst verfügbar sein, wenn enumerate() vollständig enumeriert hat? Kann mir ein Fachmann / eine Fachfrau nen Tipp geben? Viele Grüße. vom Theo Zitieren
rtrbt Geschrieben September 21, 2020 at 07:37 Geschrieben September 21, 2020 at 07:37 Moin, (Disclaimer: Bin kein JavaScript-Experte) Das Problem ist sogar noch etwas komplizierter, da du ja nicht weißt, wie viele Bricks/Bricklets vorhanden sind, das heißt rein technisch weißt du nicht, wann du fertig bist mit dem Warten auf die enumerate-Callbacks. Du kannst aber so Kriterien wie "ich weiß es sind genau X Bricks/Bricklets" oder "wenn nach 0.5 Sekunden kein neues Callback kam bin ich fertig" oder einfach "Ich warte eine Sekunde auf Callbacks" o.Ä. verwenden, das ist typischerweise gut genug. Ein Ansatz der dein Problem löst wäre, wenn das Auslösen mit .enumerate() und die Callback-Verarbeitung zwar nebenläufig ist, du aber mit await darauf warten kannst. Es würde sich also anbieten, wenn du eine Funktion schreibst, die das Array anlegt, das Callback registriert, enumerate auslöst, nach deinen Kriterien auf Antworten wartet und dann das Array zurückgibt. Diese Funktion machst du async, dann kannst du im Hauptprogramm das ganze anschieben und wenn du das Ergebnis brauchst es per await abholen. Gruß, Erik 1 Zitieren
theobald Geschrieben September 21, 2020 at 10:36 Autor Geschrieben September 21, 2020 at 10:36 Moin rtrbt, danke! Ja genau! Man weiß nicht, wieviele Bricks/Bricklets sich zurückmelden... Ich werde mich mal in das Problem vertiefen... Wenn ich eine Lösung finde, dann schreibe ich nochmal... Grüße vom Theo Zitieren
theobald Geschrieben September 22, 2020 at 10:42 Autor Geschrieben September 22, 2020 at 10:42 also mir ist es bisher leider nicht gelungen, das Problem zu lösen. Kann mir vielleicht ein JS-Profi etwas behilflich sein? Ich habe jetzt: var device_promises = []; und... // Register Connected Callback ipcon.on(Tinkerforge.IPConnection.CALLBACK_CONNECTED, async function (connectReason) { await enumerateDevices(); } ); und später... ipcon.on(Tinkerforge.IPConnection.CALLBACK_ENUMERATE, // Print incoming enumeration function(uid, connectedUid, position, hardwareVersion, firmwareVersion, deviceIdentifier, enumerationType) { const dp = new Promise(resolve => { let device = {}; if (enumerationType === Tinkerforge.IPConnection.ENUMERATION_TYPE_DISCONNECTED) { device = { uid: uid, enum_type: enumerationType, connectedUid: 0, position: 0, hardwareVersion: 0, firmwareVersion: 0, deviceIdentifier: 0 }; } else { device = { uid: uid, enum_type: enumerationType, connectedUid: connectedUid, position: position, hardwareVersion: hardwareVersion, firmwareVersion: firmwareVersion, deviceIdentifier: deviceIdentifier }; } //resolve(device); }); device_promises.push(dp); console.log(`${performance.now()} new Promise() `, dp); } ); im Hauptprogramm dann folgendes: function enumerateDevices() { ipcon.enumerate(); Promise.all(device_promises).then((values) => { console.log(`${performance.now()} Promise.all.then ${values}`); }); } bereits enumerateDevices() sollte ja mit Promise.all().then() alle pending promises abwarten, aber erstaunlicherweise wartet Promise.all() nicht, bis device_promises vorliegen, sondern bearbeitet das leere Array sofort ab und liefert keine Ergebnisse. es läuft so ungefähr... 824ms ipcon.connected ->OK 825ms enumerateDevices() ->leer 826ms Promise.all.then ->leer 844ms new Promise (pending) 846ms new Promise (pending) usw... STOP Kann mir da nochmal jmd. einen Tipp geben? Wo muss der Code berichtigt werden? Oder geht das so gar nicht? Grüße vom Theo. Zitieren
theobald Geschrieben September 22, 2020 at 13:41 Autor Geschrieben September 22, 2020 at 13:41 also ich muss noch weiter fragen. Ich verstehe das Konzept der Callbacks hier nicht so richtig. Da die Tinkerforge API weitgehend Callback-orientiert ist, sollten diese doch entsprechend den Konventionen implementiert sein. Ich habe nun versucht ipcon.on zu verketten, aber das geht nicht. ipcon.on() ist kein EventEmitter und daher kann man ihn nicht verketten mit ipcon.on(CONECCTED).on(ENUMERATE) Wäre das nicht essentiell? Denn nur wenn ipconn.on(Connected) erfolgreich wäre ist erst ipcon.authenticate() sinnvoll und danach ipcon.enumerate() und erst danach Bricklet.on(CALLBACK_HUMIDITY) etc. Wie ist es denn von Hause aus vorgesehen, diese Callbacks und ihre Rückgabewerte zu verketten? Zitieren
bernhard.graeuler Geschrieben September 22, 2020 at 14:02 Geschrieben September 22, 2020 at 14:02 Hi! Ich habe die Javascript Bindings noch nicht verwendet, aber mir scheint, dass Du erstmal nichts anderes machen willst, als die im IPConnection Example Code ausgegebenen Devices in ein Array zu schreiben, und in deinem Programm darauf zu warten, dass dies Array befüllt ist. Kommst Du vielleicht weiter, wenn Du das Beispiel entsprechend erweiterst? 1 Zitieren
theobald Geschrieben September 22, 2020 at 14:07 Autor Geschrieben September 22, 2020 at 14:07 Hi! naja mein oben geposteter Code ist ja bereits die (nicht funktionierende) Erweiterung. Ich weiss leider nicht, wo ich ansetzen soll. Ich müsste/möchte die Ergebnisse der Callbacks verketten, aber das geht so nicht, wie ich es versucht habe. Ich versuche z.B. die Aufrufe des enumerate_callbacks in ein Promise-Array zur schreiben und dieses Array dann aufzulösen. Das funktioniert aber nicht. mein Promise.all wird fullfilled bevor das array geladen wurde. Ich weiss nicht, warum! Ich finde leider auch keine Beispiele... Zitieren
theobald Geschrieben September 23, 2020 at 05:45 Autor Geschrieben September 23, 2020 at 05:45 (bearbeitet) Moin moin, also ich muss mich etwas präziser ausdrücken: Genaugenommen habe ich zwei Probleme. 1. sauberen Code schreiben ->Callback-Chain oder Promise Chain und 2. die Ergebnisse der Enumerate-Callbacks für die Laufzeit der Main Loop in einem Array speichern oder beim Reconnect aktualisieren. besonders Nr. 2. liegt mir am Herzen und ich finde keine richtige Lösung... @rtrbtgibt es keinen Kontakt zu einem Entwickler, der die Bindings entworfen hat? Der könnte doch bestimmt zwei drei Tipps geben, in welcher Richtung man suchen muss.... das wäre echt nett 😀 bearbeitet September 23, 2020 at 05:46 von theobald Zitieren
photron Geschrieben September 23, 2020 at 13:37 Geschrieben September 23, 2020 at 13:37 Also, so wie du Promise verwendest kann das nicht funktionieren. Du legst ein leeres device_promises Array an, und im Prinzip rufst direkt danach Promise.all auf ein leeres Array auf. Dieses Promise ist natürlich sofort erfüllt, denn die Enumerate Callbacks kommen erst danach an. Damit der Ansatz funktioniert musst du vor dem ipcon.enumerate() Aufruf wissen wie viele Devices vorhanden sind und die Promises vorher anlegen und nicht erst im Enumerate Callback, denn dort ist es zu spät. Wenn du nicht weißt wie viele Devices vorhanden sind kannst du das über einen Timeout lösen. Die Annahme dabei ist, dass zwischen dem ipcon.enumerate() Aufruf und dem ersten Enumerate Callback und dann den darauf noch folgenden Enumerate Callbacks jeweils weniger als eine Sekunde vergeht. Ich habe dir mal das Enumerate Example abgeändert. ExampleEnumerate_theobald.html 1 Zitieren
theobald Geschrieben September 23, 2020 at 16:02 Autor Geschrieben September 23, 2020 at 16:02 Danke! Das ist prima! Es ist viel einfacher, als mit promises. Ich bin davon ausgegangen, dass ich mit promises warten muss, bis die einzelnen Geräte antworten. Das schrittweise neue Timeout, bis das nächste Gerät antwortet, ist jedenfalls viel einfacher als mit promises. Vielen Dank! Zitieren
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.