Jump to content

Tipps für Lösung eines kniffligen Problems


Recommended Posts

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

Link zu diesem Kommentar
Share on other sites

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

Link zu diesem Kommentar
Share on other sites

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.

Link zu diesem Kommentar
Share on other sites

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?

Link zu diesem Kommentar
Share on other sites

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?

Link zu diesem Kommentar
Share on other sites

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...

Link zu diesem Kommentar
Share on other sites

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 von theobald
Link zu diesem Kommentar
Share on other sites

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

Link zu diesem Kommentar
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...