Homoran hat mich da komplett missverstanden und ist einfach dagegen. Meine Erklärungsversuche prallten an ihm ab, stattdessen wurde mit teils falschen Annahmen und Zitaten ohne Zusammenhang argumentiert.
Da bin ich raus.
Homoran hat mich da komplett missverstanden und ist einfach dagegen. Meine Erklärungsversuche prallten an ihm ab, stattdessen wurde mit teils falschen Annahmen und Zitaten ohne Zusammenhang argumentiert.
Da bin ich raus.
@bahnuhr said in async / await -> Muster Anleitung gesucht:
Habt ihr mal ein Muster mit diesem await, das halt wartet bis etwas erledigt ist, und dann zum nächsten await geht.
@htrecksler said in async / await -> Muster Anleitung gesucht:
Ich würde die await Funktion auch sehr gerne nutzen, habe mich aber noch nicht weiter damit beschäftigt.
Ich hatte auch einige Zeit gebraucht, um die async/await Logik zu verstehen
Oben hab ich schon mal versucht, zu erklären.
Weiteres Beispiel:
In einem Script will ich Datenpunkte anlegen, und danach diese auf Änderung überwachen. Die Überwachung auf Änderung soll aber nur stattfinden, nachdem die Datenpunkte angelegt sind, was mehrere Millisekunden dauern kann mit createState()
. Daher bietet sich hier super async/await an.
mainAsync();
async function mainAsync() {
try {
await createStateAsync('0_userdata.0._0_TEST.STATE_1', {name:'Test 1', type:'string', read:true, write:true, role:'state', def:'neu angelegt' });
await createStateAsync('0_userdata.0._0_TEST.STATE_2', {name:'Test 2', type:'boolean', read:false, write:true, role:'button', def:false })
// States erstellt, jetzt machen wir Subscribe
on({id: ['0_userdata.0._0_TEST.STATE_1', '0_userdata.0._0_TEST.STATE_2'], change:'any', ack:false}, async (obj) => {
log(`State '${obj.id}' changed to [${obj.state.val}]`)
});
} catch (error) {
dumpError(`[mainAsync()]`, error);
return false;
}
}
/**
* Error Message to Log. Handles error object being provided.
* @param {string} msg - (intro) message of the error
* @param {*} [error=undefined] - Optional: Error object or string
*/
function dumpError(msg, error=undefined) {
if (!error) {
console.error(msg);
} else {
if (typeof error === 'object') {
if (error.stack) {
log(`${msg} – ${error.stack}`, 'error');
} else if (error.message) {
log(`${msg} – ${error.message}`, 'error');
} else {
log(`${msg} – ${JSON.stringify(error)}`, 'error');
}
} else if (typeof error === 'string') {
log(`${msg} – ${error}`, 'error');
} else {
log(`[dumpError()] : wrong error argument: ${JSON.stringify(error)}`, 'error');
}
}
}
@homoran said in Deutlich bessere Integration Home Assistant in ioBroker:
deswegen auch alles in deutsch
Danke für deine Antwort . Aber wie meinst du das? Wäre doch cool, z.B. darüber auch mehr Entwickler etc. zu akquirieren, und mehr internationale Leute dazu zu bringen, zu ioBroker zu wechseln. Die Adapter-Dokus sind doch eh alle in Englisch, wie auch die Entwickler-Doku. Also Einstieg als nicht Deutsch-Sprechender sollte super easy sein
Ich wünsche dir herzlichst gute Besserung, @Homoran!
Bin bei dir, dass die Installations-Doku verbesserungswürdig ist.
Aber "once completed", hat man alle Möglichkeiten, da alle Adapter erst mal in Englisch sind.
@homoran said in Deutlich bessere Integration Home Assistant in ioBroker:
und unser großer Vorteil ist, dass alles - insbesondere das Forum- auf Deutsch ist.
Das wird uns immer wieder von Umsteigern von HASS, FHEM und anderen lobend erwähnt
Stimme dir absolut zu, ist ein mega Vorteil, da sich einige mit Englisch schwer tun. Aber das spricht doch nicht dagegen, auch mehr International hin zu öffnen?
Gerade die Entwicklung und Weiterentwicklung von Adaptern, Reverse Engineering, usw. Da würde eine größere Beteiligung echt mega gut tun. Geräte ändern sich, ioBroker-Adapter haben Fehler oder berücksichtigen nicht schnell genug neue Hardware, bestehende Entwickler machen nicht mehr weiter, usw. Je mehr Entwickler, desto besser. Und je mehr User, desto mehr Entwickler folgen wohl.
So meine Gedanken Alle bestehenden Adapter müssen auch ständig weiter entwicklelt werden, neue Node.JS-Versionen, Upgrades von Modulen, Integration neuer Hardware, usw. Je mehr Helfer, desto besser, denke ich
@homoran
Vielen Dank für unsere Konversation.
Aber ich denke, ein weiterer Austausch zwischen uns beiden hier in diesem Thread ergibt keinen wirklichen Sinn. Wir schreiben leider komplett aneinander vorbei. Es geht mir nicht um Rechtfertigung von VIS, der einfachen Installation, etc. Beide, also ioBroker, als auch Home Assistant, sind sehr erwachsene Systeme. Manch Unterschiede und mehrere klare Vorteile von ioBroker habe ich ja oben bereits dargestellt, aber hier geht es nicht um einen Vergleich, siehe bitte ursprünglichen Beitrag oben.
Siehe auch:
Add Google Blocky to Home Assistant
In HA ist es wirklich nicht einfach, komplexere Automatisierungen zu machen, und im Zweifel wird auf die nodeRED-Integration verwiesen.
Auch hier ist ioBroker deutlich weiter.
@bahnuhr said in async / await -> Muster Anleitung gesucht:
@hendrick sagte in async / await -> Muster Anleitung gesucht:
Du ruft die Funktion "weiter()" per await weiter();
Ja, aber nur weil du im Beispiel den:
await setStateAsync('0_userdata.0.test.123.Datei-ist-kopiert', {val:true, ack:false});
auch mit await aufgerufen hast.Wusste nicht, dass da ein Unterschied besteht.
setStateAsync()
ist bereits eine asynchrone Funktion von ioBroker.
Um async zu nutzen, rufst du diese per await setStateAsync()
auf.
weiter()
ist deine eigene Funktion, nicht von ioBroker, und nicht von node.js oder einem Modul, hier musst du dieser Funktion selbst sagen, dass sie async ist, in dem du ein async function weiter()
machst. Sonst ist sie nicht async und wird einfach so abgefeuert, und es wird auf kein Ergebnis gewartet.
@bahnuhr said in async / await -> Muster Anleitung gesucht:
Fazit:
Das ganze ist verdammt verwirrend und irreführend für mich.
Wenn ich mir das Script so anschaue, dann sind das nur für den kopier Befehl ca. 30 Zeilen (ohne sie jetzt genau gezählt zu haben).
Mein derzeitiges kopier-Script hat 3 Zeilen + timeout Zeilen.
Achtung
Ich, und wohl jeder hier, erklären dir gerne alles. Sag weiterhin gerne Bescheid, wo du konkret Fragen hast.
Viele Script-Beispiele hier im Forum sind "Quick&Dirty", aber funktionieren halt einfach
Einstieg in async/await bedeutet auch, dass du DEUTLICH besseren Quellcode bekommst. Im Idealfall verifizierst da z.T. auch mehr, und wirst mehr diszipliniert, zu prüfen.
Beispiel:
setState('XYZ', getState('ABC').val);
Hier wird einfach so ein Datenpunktwert ohne Prüfung in einen anderen Datenpunkt gesetzt. Egal, ob der DP überhaupt vorhanden ist, egal, ob der Ziel-Datenpunkt kompatibel ist zum Datentyp, etc.
Im Idealfall wartet man hier erst mal ab, ob und was der getState() überhaupt zurück liefert, und reagiert dann.
Das hat jetzt nicht unbedingt mit async/await zu tun, aber Prüfungen usw. verlängeren den Quellcode, aber ersparen dir viel Ärger in der Zukunft.
Auch die Nutzung von try/error wie in den obigen Beispielen.
JA - Quellcode wird deutlich länger. Aber auch deutlich sicherer.
Gute Frage.
Die async/await-Abarbeitung im Script ist sauber.
Hier nur kleine Anmerkung:
Du ruft die Funktion "weiter()" per await weiter();
auf, allerdings ist diese Funktion "weiter()" nicht async definiert. Hat so jetzt keine Auswirkung im Script, aber besser machst du statt function weiter()
ein async function weiter()
, weil du mit await weiter();
implizierst, dass eine async Funktion aufgerufen wird, was ja so nicht der Fall ist.
Jetzt aber zur Thematik:
Ich habe das jetzt nicht mit einem großen File getestet. Aber so wie sich der Code in copyFileAsync()
liest, wird mittels wr.on('finish', resolve);
erst dann ein erfolgreiches Schreiben zurückgemeldet, wenn der Prozess abgeschlossen ist.
Somit wundert es mich, dass du vorher schon die Rückmeldung bekommst.
Du könntest das mal überprüfen, in dem du im Script die Dateigröße der Quelle mit der Dateigröße des Ziels vergleichst in deiner Funktion weiter()
und diese als Log mal ausgibst. Dann weißt du, ob lt. Script wirklich kopiert wurde.
Lange Rede, kurzer Sinn: dies hat nichts mit dem Script-Aufbau zu async/await zu tun, sondern könnte bei dir fs.createWriteStream()
schon vorzeitig ein finish
liefern, obwohl noch gar nicht fertig kopiert wurde.
Seltsam, aber wäre es wert, näher einzusteigen.
@bahnuhr said in async / await -> Muster Anleitung gesucht:
Wenn noch jemand Beispiele hat nur her damit.
Melde dich einfach, wenn du wo hängst. Ich denke das mit createStateAsync() ist ein gutes Beispiel.
Du kannst das auch in eine Funktion kapseln, also:
mainAsync();
async function mainAsync() {
try {
const createStateResult = await createSomeStates();
if (createStateResult) {
log('States erfolgreich erstellt, wir machen weiter.');
} else {
log('Fehler bei State-Erstellung. Wir brechen ab', 'warn');
return;
}
// States erstellt, jetzt machen wir Subscribe
on({id: ['0_userdata.0._0_TEST.STATE_1', '0_userdata.0._0_TEST.STATE_2'], change:'any', ack:false}, async (obj) => {
log(`State '${obj.id}' changed to [${obj.state.val}]`)
});
} catch (error) {
dumpError(`[mainAsync()]`, error);
return false;
}
}
/**
* @return {Promise<boolean>}
*/
async function createSomeStates() {
try {
await createStateAsync('0_userdata.0._0_TEST.STATE_1', {name:'Test 1', type:'string', read:true, write:true, role:'state', def:'neu angelegt' });
await createStateAsync('0_userdata.0._0_TEST.STATE_2', {name:'Test 2', type:'boolean', read:false, write:true, role:'button', def:false })
return true;
} catch (error) {
dumpError(`[createSomeStates()]`, error);
return false;
}
}
/**
* Error Message to Log. Handles error object being provided.
* @param {string} msg - (intro) message of the error
* @param {*} [error=undefined] - Optional: Error object or string
*/
function dumpError(msg, error=undefined) {
if (!error) {
console.error(msg);
} else {
if (typeof error === 'object') {
if (error.stack) {
log(`${msg} – ${error.stack}`, 'error');
} else if (error.message) {
log(`${msg} – ${error.message}`, 'error');
} else {
log(`${msg} – ${JSON.stringify(error)}`, 'error');
}
} else if (typeof error === 'string') {
log(`${msg} – ${error}`, 'error');
} else {
log(`[dumpError()] : wrong error argument: ${JSON.stringify(error)}`, 'error');
}
}
}
@bahnuhr said in async / await -> Muster Anleitung gesucht:
Habt ihr mal ein Muster mit diesem await, das halt wartet bis etwas erledigt ist, und dann zum nächsten await geht.
@htrecksler said in async / await -> Muster Anleitung gesucht:
Ich würde die await Funktion auch sehr gerne nutzen, habe mich aber noch nicht weiter damit beschäftigt.
Ich hatte auch einige Zeit gebraucht, um die async/await Logik zu verstehen
Oben hab ich schon mal versucht, zu erklären.
Weiteres Beispiel:
In einem Script will ich Datenpunkte anlegen, und danach diese auf Änderung überwachen. Die Überwachung auf Änderung soll aber nur stattfinden, nachdem die Datenpunkte angelegt sind, was mehrere Millisekunden dauern kann mit createState()
. Daher bietet sich hier super async/await an.
mainAsync();
async function mainAsync() {
try {
await createStateAsync('0_userdata.0._0_TEST.STATE_1', {name:'Test 1', type:'string', read:true, write:true, role:'state', def:'neu angelegt' });
await createStateAsync('0_userdata.0._0_TEST.STATE_2', {name:'Test 2', type:'boolean', read:false, write:true, role:'button', def:false })
// States erstellt, jetzt machen wir Subscribe
on({id: ['0_userdata.0._0_TEST.STATE_1', '0_userdata.0._0_TEST.STATE_2'], change:'any', ack:false}, async (obj) => {
log(`State '${obj.id}' changed to [${obj.state.val}]`)
});
} catch (error) {
dumpError(`[mainAsync()]`, error);
return false;
}
}
/**
* Error Message to Log. Handles error object being provided.
* @param {string} msg - (intro) message of the error
* @param {*} [error=undefined] - Optional: Error object or string
*/
function dumpError(msg, error=undefined) {
if (!error) {
console.error(msg);
} else {
if (typeof error === 'object') {
if (error.stack) {
log(`${msg} – ${error.stack}`, 'error');
} else if (error.message) {
log(`${msg} – ${error.message}`, 'error');
} else {
log(`${msg} – ${JSON.stringify(error)}`, 'error');
}
} else if (typeof error === 'string') {
log(`${msg} – ${error}`, 'error');
} else {
log(`[dumpError()] : wrong error argument: ${JSON.stringify(error)}`, 'error');
}
}
}
@htrecksler said in async / await -> Muster Anleitung gesucht:
Da ist ja wieder ein Sleep-Befehl? Oder ist der in dem Fall Kosmetik?
Das war nur Kosmetik, aber war in diesem Fall wohl verwirrend, denn die sleep braucht es nicht.
@bahnuhr said in async / await -> Muster Anleitung gesucht:
function Datei_kopieren(von, nach)
Lass mal mit dieser Funktion anfangen. Diese muss auf async/await umgeschrieben werden.
Hier ein komplettes Beispiel:
const fs = require('fs');
mainAsync();
async function mainAsync() {
try {
/**
* Hier kopieren wir die Datei.
*/
log(`Trying to copy file...`);
const fileSource = '/opt/iobroker/_test1/pic.png';
const fileTarget = '/opt/iobroker/_test1/pic-copy.png';
const fileCopied = await copyFileAsync(fileSource, fileTarget);
if (!fileCopied) {
// Beim Kopieren trat ein Fehler auf.
log(`Datei '${fileSource}' konnte nicht nach '${fileTarget}' kopiert werden.`, 'warn');
log(`Script wird beendet.`, 'warn');
return false;
}
log(`File copied.`);
/**
* Datei erfolgreich kopiert, hier geht's weiter
*/
// HIER GEHT ES WEITER
// ...
// Setze z.B. jetzt einen Datenpunkt
// await setStateAsync('0_userdata.0.test.123.Datei-ist-kopiert', {val:true, ack:false});
} catch (error) {
dumpError(`[mainAsync()]`, error);
return false;
}
}
/**
* Copy file async - https://stackoverflow.com/a/30405105
* @param {string} source /path/to/file
* @param {string} target /path/to/file
* @return {Promise<boolean>} true if successful, false if not
*/
async function copyFileAsync(source, target) {
const rd = fs.createReadStream(source);
const wr = fs.createWriteStream(target);
try {
await new Promise( (resolve, reject) => {
rd.on('error', reject);
wr.on('error', reject);
wr.on('finish', resolve);
rd.pipe(wr);
});
return true;
} catch (error) {
rd.destroy();
wr.end();
dumpError(`[copyFileAsync()]`, error);
return false;
}
}
/**
* Error Message to Log. Handles error object being provided.
* @param {string} msg - (intro) message of the error
* @param {*} [error=undefined] - Optional: Error object or string
*/
function dumpError(msg, error=undefined) {
if (!error) {
console.error(msg);
} else {
if (typeof error === 'object') {
if (error.stack) {
log(`${msg} – ${error.stack}`, 'error');
} else if (error.message) {
log(`${msg} – ${error.message}`, 'error');
} else {
log(`${msg} – ${JSON.stringify(error)}`, 'error');
}
} else if (typeof error === 'string') {
log(`${msg} – ${error}`, 'error');
} else {
log(`[dumpError()] : wrong error argument: ${JSON.stringify(error)}`, 'error');
}
}
}
Zur Erklärung:
In der Funktion mainAsync()
rufst du nach und nach all deine asynchronen Funktionen etc. auf.
Im Beispiel rufen wir also zunächst copyFileAsync()
auf. Sobald erfolgreich kopiert, kannst du dann weitere Funktionen aufrufen, wie z.B. mit await setStateAsync()
einen Datenpunkt setzen, usw.
test();
async function test() {
try {
await sleep(3*1000); // Erst mal 3 Sekunden warten
await setStateAsync('PFAD ZUM DATENPUNKT', {val:true, ack:false});
await sleep(1*1000); // Eine Sekunde warten
await setStateAsync('PFAD ZUM DATENPUNKT', {val:true, ack:false});
} catch (error) {
return;
}
}
Noch eine Error-Fehlerausgabe ins log erforderlich. Aber so wäre ein Grundkonstrukt.
Mag wer helfen, bitte?
Wollte schon auf Github ein Issue aufmachen, aber ist ja nur eine Frage. Daher dachte ich, hier im Forum wird geholfen.
Danke!
Würde mich über Hilfe freuen, danke
Es reicht auch schon ein kurzer Hinweis etc., wo ich weiter schauen kann.
@2hot4you said in Ring Doorbell externe Signalisierung:
Meine Idee wäre den Datenpunkt ring.0.doorbell_46xxxxxxx.state abzugreifen, und dann eine Aktion bei ringring auszuführen, z.b. ein Tasmota Relais und MP3 Sound.
Ich nutze zwar die Hardware nicht, aber das geht doch einfach im JavaScript-Adapter, entsprechend anpassen natürlich und ggf. mehrfaches Klingeln abfangen.
on({id:'ring.0.doorbell_46xxxxxxx.state', val:true, ack:true}, (obj) => {
setState('HIER ZIEL-DATENPUNKT', true);
});