Jump to content

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 to post
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

  • Thanks 1
Link to post
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 to post
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 to post
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 to post
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 😀

 

Edited by theobald
Link to post
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

  • Like 1
Link to post
Share on other sites

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!

Link to post
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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...