NEWS
[gelöst] History per script auslesen: Wie warten auf Daten?
-
Hallo,
ich möchte eine Tabelle mit Daten aus der History befüllen.
Dazu frage ich die Daten mitsendTo('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }, function (result) { }
ab.
Nun ist meine "Abfüllung" der Daten fertig, bevor ich die Daten von sendTo zurückbekomme. Offenbar läuft das asynchron. Wie kann ich warten, bis ich die Daten bekomme? -
@delphinis
Hab einen Weg gefunden:
Ich fülle meine Daten am Ende der Funktion (noch im callback, anstatt ausserhalb) ab.
Es würde mich trotzdem für andere Fälle interessieren, wie man auf eine Antwort der History warten kann.... -
@delphinis nimm
async function history(){ let result = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } } return result } async function test(){ let result = await history(); mach_was_mit_result(result) } test();
-
@delphinis bitte den geänderten Beitrag beachten, da fehlte noch was Entscheidendes!
-
@delphinis said in History per script auslesen: Wie warten auf Daten?:
sendTo('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }, function (result) { // ab hier callback }
Der Befehl sendTo hat 4 Parameter
- Die Adapterinstanz an die was gesendet werden soll
- der Befehl der ausgeführt werden soll
- evtl Parameter
- Eine Callback Funktion die aufgerufen wird, wenn der andere Adapter alles ausgeführt hat.
Daher, wenn ich deine eigene Antwort richtig interpretiere, hast du das schon selbst herausgefunden.
Fastfoot hat noch auf eine weitere Variante von sendTo hingewiesen.
sendToAsync ist die Promise-Version der Funktion. da kann dann mit await darauf gewartet werden. Der Einsatz von promises kann einen Programmablauf klarer darstellen, da ansonsten bei mehreren aufeinander gestaffelten Callback-Funktionen es schnell unübersichtlich wird. -
@fastfoot
Hallo, ich hab das mal versucht, bin aber nicht weitergekommen und hab's mal zurückgestellt. Nun hab ich wieder etwas Zeit und möchte dort weiterkommen.
Das Problem ist nun, dass ich nicht wirklich an die Daten komme, weil die Struktur offenbar verschachtelt ist und in der Test Funktion nicht mehr bekannt ist. Ich kann also nicht mit result.result die Daten abfragen:
Hier nochmal mein Code:
const Ereignisdp = 'alias.0.TH-OutNO.Temp'; async function history(){ let result = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }); return result } async function test(){ let result = await history(); for (var i = 0; i < result.result.length; i++) { console.log(new Data(result.result[i].ts + ', ' + result.result[i].val)); } } test();
Vielleicht ist die Struktur je nach Resultat auch nicht immer gleich?
Ich arbeite übrigens wenn es geht mit Typescript weil ich das von anderen Sprachen gewohnt bin. Wenn ich also wüsste wie die Klasse aufgebaut ist, könnte mir das ev. weiterhelfen.
In der Doku konnte ich das nicht finden, und typeof(result) liefert mir auch nur "object"
Eine Lösung in Javascript ist mir aber auch recht. -
a)
async function history(){ let result = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }); log(JSON.stringify(result) }
Dann hier aus der Antwort einen type bauen lassen und dem mit:
a.1)
mein Favorit: (KA ob das im JS-Adapter geht)// typen sind nur beispiele haben nix mit der wirklichen Antwort von history.0 zu tun type IconScaleElement = { val_min: number; val_max: number; val_best?: number; log10?: 'max' | 'min'; mode?: 'mixed' | 'hue' | 'cie'; }; // hier validieren dass die Daten deinen Typenannahmen entsprechen function isIconScaleElement(F: any): F is IconScaleElement { return F && 'val_min' in (F as IconScaleElement) && 'val_max' in (F as IconScaleElement); } async function history(): IconScaleElement{ let result:any = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }); if (isIconScaleElement(result) return result; else throw new Error('ups something goes wrong!'); }
a.2)
async function history(): myType { let result = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }); return result as myType; }
verwenden.
b)
async function history(): any{ let result:any = await sendToAsync('history.0', 'getHistory', { id: Ereignisdp, options: { end: Date.now(), count: 20, } }); return result // ka ob hier auch noch ein as any hin muß }
-
@ticaki
Danke für den Hinweis mit log(JSON.stringify(result)
so kann ich da Daten nun schon in der funktion getHistory abholen. Das Abfüllen funktioniert eigentlich, aber das mit dem await nicht:class Data { ts: number; value: any; constructor(ts:number, value:any) { this.ts = ts; this.value = value; } } async function getHistoryData(from:number, to:number, DP:string, resArray:Array<Data>) { let startTime = Date.now(); sendTo('history.0', 'getHistory', { id: DP, options: { start: from, end: to, aggregate: 'onchange' } }, function (result) { console.log('Zeit für History-Daten holen: ' + (Date.now() - startTime) + 'ms'); let count = 0; for (var i = 0; i < result.result.length; i++) { resArray.push(new Data(result.result[i].ts, result.result[i].val)); ++count; } console.log('Anzahl in getHistory:' + count); }); } async function get(){ await getHistoryData(new Date('2024-06-23 00:00').getTime(), new Date('2024-06-23 23:59:59').getTime(), 'alias.0.TH-OutNO.Temp', dataNO); // hier sind die Daten noch nicht vorhanden! dataNO.forEach(function (data) { console.log(data.ts + '; ' + data.value); }); } let dataNO:Array<Data> = []; get();
Aber was ich nicht begreife ist: Eigentlich sollte doch mit await getHistoryData auf das abarbeiten gewartet werden. die Daten sind aber nach diesem Aufruf noch nicht da. Man müsste das noch abwarten. Ich dachte await sei genau dazu da, oder verstehe ich das falsch?
Hab dazu folgendes gefunden:
"The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or at the top level of a module."
Ich wollte dem Funktionsaufruf get() auch noch ein await voranstellen um zu testen, ob es daran liegt, aber das gibt mir einen Interpreter-Fehler:
"
'await' expressions are only allowed at the top level of a file when that file is a module, but this file has no imports or exports. Consider adding an empty 'export {}' to make this file a module.(1375)
"
"
Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', or 'nodenext', and the 'target' option is set to 'es2017' or higher.(1378)
"
Ich weiss jetzt nicht ob das überhaupt etwas bringen würde, aber ich wüsste nun auch nicht wo man 'module' option so setzen kann.PS: ich brauche die Daten aber ausserhalb der Funktion getHistoryData(), da ich sie mit anderen History-Daten, welche auch geholt werden müssen, verrechnen kann.
Ich hab's mal mit await sleep(50); versucht. Tatsächlich sind die Daten danach vorhanden, obwohl auch hier auf top level dieser Interpreter-Fehler kommt?!
Nur ist das lediglich für einen Versuch gut, denn das Holen dauert mal 40, mal 100ms... -
@delphinis
Du benutzt sendTo() das ist eine Funktion mit callback. Dann könntest du mit Promise arbeiten. Einfach ist es aber ohne callback mitconst result = await sendToAsync()
Wieso sollte man await auf der oberen Ebene benutzen. kannst doch einfach alles in
async main(){}
packen und am ende vom skript einmain()
-
@ticaki
Super. Das scheint zu funktionieren. Besten dank!