Aide async/await dans les scripts


#1

@pierre-gilles
Je vais t’embêter une nouvelle fois car je rencontre depuis la MAJ un problème sur des scripts qui utilisent des méthodes peu orthodoxes.

Voici un exemple de script :

var now1 = new Date();
gladys.param.setValue({ name: “DernDetSDB”, value: now1 });

setTimeout(function(){
gladys.deviceType.getById({ id: 70}).then((doucheEnCours) => {
var now = new Date();
var Det = gladys.param.getValue(“DernDetSDB”);
var DD = Det.value();
var eteindreApres = new Date(DD.getFullYear(), DD.getMonth(), DD.getDate(), DD.getHours(), DD.getMinutes(), DD.getSeconds()+55);
if (eteindreApres < now && doucheEnCours.lastValue === 0) gladys.script.exec({id: 44});
});
}, 6000);

C’est un script modifié pour le débug, qui allume un devicetype et l’éteint au bout de 60 secondes, sauf si il est lancé à nouveau entre temps.

Je rencontre un problème depuis la MAJ de gladys sur les lignes suivantes

var Det = gladys.param.getValue("DernDetSDB");
var DD = Det.value();

L’erreur obtenue est

Summary

0|gladys | Unhandled rejection TypeError: cannot get fulfillment value of a non-fulfilled promise
0|gladys | See http://goo.gl/MqrFmX
0|gladys | at PromiseInspection.value (/home/pi/gladys/node_modules/bluebird/js/release/synchronous_inspection.js:22:15)
0|gladys | at Promise.value (/home/pi/gladys/node_modules/bluebird/js/release/synchronous_inspection.js:84:18)
0|gladys | at gladys.deviceType.getById.then (evalmachine.:13:21)
0|gladys | at tryCatcher (/home/pi/gladys/node_modules/bluebird/js/release/util.js:16:23)
0|gladys | at Promise._settlePromiseFromHandler (/home/pi/gladys/node_modules/bluebird/js/release/promise.js:512:31)
0|gladys | at Promise._settlePromise (/home/pi/gladys/node_modules/bluebird/js/release/promise.js:569:18)
0|gladys | at Promise._settlePromise0 (/home/pi/gladys/node_modules/bluebird/js/release/promise.js:614:10)
0|gladys | at Promise._settlePromises (/home/pi/gladys/node_modules/bluebird/js/release/promise.js:693:18)
0|gladys | at Async._drainQueue (/home/pi/gladys/node_modules/bluebird/js/release/async.js:133:16)
0|gladys | at Async._drainQueues (/home/pi/gladys/node_modules/bluebird/js/release/async.js:143:10)
0|gladys | at Immediate.Async.drainQueues (/home/pi/gladys/node_modules/bluebird/js/release/async.js:17:14)
0|gladys | at Immediate.args.(anonymous function) (/usr/lib/node_modules/pm2/node_modules/event-loop-inspector/index.js:138:29)
0|gladys | at runCallback (timers.js:810:20)
0|gladys | at tryOnImmediate (timers.js:768:5)
0|gladys | at processImmediate [as _immediateCallback] (timers.js:745:5)

Y a t il eu des modifications qui bloquent l’utilisation que je fais ici ?
J’ai remarqué que si je supprime les () pour avoir seulement var DD = Det.value; je n’ai plus cette erreur. En revanche, impossible d’utiliser mes scripts, je n’arrive pas a relire mes variables “globales maison” car une fois les guillemets supprimés, quand je fais

var Det = gladys.param.getValue(“DernDetSDB”);
var DD = Det.value;
console.log(DD);

J’ai dans la console[Function] et pas mon objet date :cold_sweat:

Il me semble que Gladys a aussi planté et donc redémarré plusieurs fois quand j’ai causé ces erreurs a la chaine, quand j’étais devant un detecteur.

Merci d’avance :slight_smile:


#2

Je ne comprends pas comment ça a pu fonctionner un jour ça :grin:

Ton code ne peut pas marcher!

var Det = gladys.param.getValue(“DernDetSDB”);
var DD = Det.value();

gladys.param.getValue renvoie une Promise. Donc soit tu fais un .then((value) => { }) pour récupérer la valeur, soit tu utilises async/await.

Exemple:

(async () => {
    await gladys.param.setValue({ name: 'DERN_SET_SDB', value: 'uneValeur' });
    const myValue = await gladys.param.getValue('DERN_SET_SDB');
    console.log(myValue);
})();

J’aimerais bien t’aider mais je vais avoir besoin de plus d’explication sur exactement ce que tu souhaites faire et comment tu lances ce script.


#3

Exellent, pourtant ça fonctionnait super bien jusqu’a la mise a jour :smiley: :smiley: Je récupérait bien la date contenue dans le paramètre avec la fonction value(). Alors pourquoi, c’est l’expérimentation qui me l’a dis :rofl:

Du coup, si j’ai bien compris, les ‘promise’ sont plus ou moins comme ceci :

gladys.deviceType.getById({ id: 2}).then((V2) => {
gladys.deviceType.getById({ id: 3}).then((V3) => {
gladys.deviceType.getById({ id: 4}).then((V4) => {
gladys.deviceType.getById({ id: 5}).then((V5) => {
gladys.deviceType.getById({ id: 6}).then((V6) => {
gladys.deviceType.getById({ id: 7}).then((V7) => {
gladys.deviceType.getById({ id: 8}).then((V8) => {
gladys.deviceType.getById({ id: 83}).then((V83) => {
gladys.deviceType.getById({ id: 11}).then((V11) => {

Summary
if (V2.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 2, value: 0});}, 0);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 2, value: 0});}, 2700);
}
if (V3.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 3, value: 0});}, 300);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 3, value: 0});}, 3000);
}
if (V4.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 4, value: 0});}, 600);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 4, value: 0});}, 3300);
}
if (V5.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 5, value: 0});}, 900);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 5, value: 0});}, 3600);
}
if (V6.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 6, value: 0});}, 1200);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 6, value: 0});}, 3900);
}
if (V7.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 7, value: 0});}, 1500);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 7, value: 0});}, 4200);
}
if (V8.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 8, value: 0});}, 1800);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 8, value: 0});}, 4500);
}
if (V83.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 83, value: 0});}, 2100);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 83, value: 0});}, 4800);
}
if (V11.lastValue == 1) {
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 11, value: 0});}, 2400);
    setTimeout(function(){ gladys.deviceType.exec({devicetype: 11, value: 0});}, 5100);
}

});
});
});
});
});
});
});
});
});

Dans ce script, je me sert également du .then((value) => { }) pour la récup de valeurs. On est d’accord que c’est sale ! Du coup, concrètement ce que je cherche a faire dans ma logique, c’est d’obtenir des variables dans mes différents script qui prennent les données contenues dans mes paramètres/deviceTypes, …
Je souhaite faire

Var etatlampe = gladys.deviceType.getById({ id: IdDeLaLampe}); (format booléen)
Var DerniereDetection = gladys.param.get(“DERN_SET_SDB”); (Je récupère un format Datetime)

mais je ne dois pas avoir la bonne méthode :stuck_out_tongue_winking_eye: après je suis preneur d’une autre solution plus ‘light’ si cela existe ^^ le but c’est de pouvoir faire des structures avec des conditions/comparaisons avec les paramètres ou états de devicetypes.

EDIT : Ce sont des scripts que je lance, soit lors d’une détection de mouvement, soit après X temps sans détection, pour mettre à 1 ou à 0 certains deviceTypes. J’utilise dans mon premier scipt les paramètres de gladys afin de sauver une date lors du dernier lancement du script, pour ne pas éteindre une lampe si jamais il y a eu une nouvelle détection et donc un lancement de ce script avant la fin du setTimout (de 60 secondes à la base, j’ai mis 6 secondes pour les tests).


#4

Dans ce cas inspire toi des async/await que j’ai posté dans mon précédent message, c’est 100% plus propre que les .then partout :slight_smile: Essaie de refaire ton script avec les await


#5

Bon je galère :rofl:
Je ne comprends pas bien le fonctionnement. Il faut que tout mon script soit dans un gros async() avec plusieurs await de plusieurs variables, ou a chaque variable dont j’ai besoin je remet un groupe async() await poiur aller la chercher ?

Fin dans les deux cas, je manque de talent pour les mettre en place, ton code plus haut me renvoie des erreurs, et j’ai l’impression qu’il ne prends pas les await en compte ?

image

mon meilleur resultat niveau erreurs :
image

Et pourquoi tu as mis myValue en ‘const’ ? :slight_smile:

Désolé, je me doute que tu n’a pas bien le temps de t’occuper de pb comme ça ^^’


#6

value: ‘uneValeur’ ne serait pas à modifier ?


#7

Si mais ça n’a rien a voir dans ce problème. C’est une chaîne de caractères sans importance :slight_smile:

EDIT : Bon, il y a vraiment un truc qui ne vas pas, je peux déclarer une variable ‘async’ et ‘await’ sans avertissement ou erreur, je ne pense pas que ce soit normal, ou alors c’est que je ne peux pas les utiliser en script :persevere:


#8

Bon du coup je fais avec des .then. Même pour lui faire reconnaître une date il a fallu que je fasse des modifs, je préférait mon fonctionnement anormal avant :rofl:

Si quelqu’un a besoin, voici comment j’ai fait, sachant que j’ai besoin de récupérer une Date a partir des paramètres :

gladys.param.getValue("DernDetSDB").then((Datedetection) => {

var DD = new Date(Datedetection);
//mon script

});

#9

par curiosité tu as installé Gladys comment? Pour avoir ce script qui fonctionne (il fonctionne nickel chez moi) il faut être en version de Node.js >= 8. L’image Raspbian Gladys l’est en tout cas…


#10

Ah ! bien vu. J’ai installé gladys manuellement sur un raspbian, mais ce qui est bizarre c’est que j’ai une version de node “ancienne” alors que mon install date d’octobre 2018… J’ai du merder.
Alors, node -v me réponds 8.15, sachant que je pensais avoir une version 11.X je n’y comprends pas grand chose
Et, pire, je comprends encore moins le npm node -v qui me renvoie une version 6.7.0 !
C’est normal que j’en ai plusieurs :rofl: ?
Je vais regarder pour mettre tout ça a jour…

EDIT : J’y comprends rien
image


#11

Si Node est en version >= 8 alors c’est censé être bon! Il doit y avoir une merde dans tes scripts. Post tes scripts exact (et je dis bien exact) ici + tes logs d’erreurs, on va voir ça.

npm node -v te retourne la version de NPM, le gestionnaire de packages. 6.7.0 c’est normal.


#12

Dans mon message de ce matin j’ai fais la MAJ de Node 8.15 à Node 11.8, quelle erreur je viens de passer 3h a tout remettre en ordre (en testant Node 10.15.1 au passage…) Aucun moyen de faire fonctionner le module Speak avec une version différente de 8.15. Retour à la case départ et en Node 8.15.0.

image
J’ai remis ce script copié collé de ton message, et avec peu d’espoir l’ai exécuté… Surprise, j’ai exactement le bon résultat dans la console “uneValeur”
image
Ici j’ai donc bien “uneValeur” de ton exemple et je récupère aussi une date complète, donc j’obtiens également 2019 dans la console.

Je comprends de moins en moins de choses… L’afficheur web du script me dis bien qu’il y a un problème non ? et il est ou le missing semicolon ??? :joy::joy:
Tu me conseille de tout refaire comme ça ? (j’ai les .then qui fonctionnent maintenant… je gagne quelque chose ?)

Si ma fonction est longue, je met une grosse fonction “async” sur tout le script pour utiliser les await ? ça gênera pas autre chose ? Les set devicetypes et set paramètres ont besoin du await ? je ne le mets pas et ça marche mais je suis novice :smile: (je viens de comprendre, ça ne se mets pas a jour “en tps réel” sans le await ! il faut réexecuter le script.)

EDIT : Rajout de ma touche perso :
image

resultat, pas d’erreur non plus : image et rien d’autre

Normal :slight_smile: ?

Question à part, tu penses que node 11.X nous apporte quelque chose (à part des incompatibilités :rofl:) avec notre usage du langage ? Ce serait plus performant ?


#13

L’afficheur web ne gère pas la syntaxe async/await je crois, mais c’est que de la vue! Derrière Gladys gère bien le async/await :slight_smile: D’où les warning ^^ Il faudrait mettre à jour la lib qu’on utilise pour l’éditeur ou juste mettre la bonne configuration pour gérer l’ES6 avec async/await.

Oui, la fonction async qui wrap sert juste à autoriser l’usage du await à l’intérieur. Mets là autour de tout ton script.

Toute les fonctions de Gladys sont asynchrones, donc oui il faut des await si tu veux attendre que le code ait bien fini de s’exécuter.

.then ou await c’est la même chose, c’est juste une syntaxe différente mais ça fait la même chose.

Je trouve personnellement await plus clair.

waaa ne fait pas ça :sweat_smile: ne donne pas des valeurs à des mots clés réservés Javascript.


#14

Parfait merci beaucoup des explications :blush: promis j’arrête de redéfinir les mots clés ! C’est surtout que généralement tu n’a pas le droit de le faire donc bon j’essaie voir :rofl:

Non en vrai c’est plus clair les await et ça simplifie le code, je vais certainement réécrire mes scripts au fur et à mesure :wink:


#15

Salut !

Je suis en train de reprendre doucement mes scripts et j’ai une question supplémentaire, voici un script :

Summary
(async () => {
const V2 = await gladys.deviceType.getById({ id: 2});//Table de nuit
const V3 = await gladys.deviceType.getById({ id: 3});//Bur L
const V4= await gladys.deviceType.getById({ id: 4});//lit
const V5= await gladys.deviceType.getById({ id: 5});//Porte
const V6 = await gladys.deviceType.getById({ id: 6});//Bur J
const V7 = await gladys.deviceType.getById({ id: 7});//Ecl soir
const V8 = await gladys.deviceType.getById({ id: 8});//Ecl télé
const V83 = await gladys.deviceType.getById({ id: 83});//Ecl doux
const V11 = await gladys.deviceType.getById({ id: 11});//Ecl tout salon
const V9 = await gladys.deviceType.getById({ id: 9});//Ecl ON SALON
var timer=0;
    if (V2.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 2, value: 0});}, timer);
    }
    if (V3.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 3, value: 0});}, timer+=300);
    }
    if (V4.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 4, value: 0});}, timer+=300);
    }
    if (V5.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 5, value: 0});}, timer+=300);
    }
    if (V6.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 6, value: 0});}, timer+=300);
    }
    //REDONDANCE + ECL OFF
   if (V2.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 2, value: 0});}, timer);
    }
    if (V3.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 3, value: 0});}, timer+=300);
    }
    if (V4.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 4, value: 0});}, timer+=300);
    }
    if (V5.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 5, value: 0});}, timer+=300);
    }
    if (V6.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 6, value: 0});}, timer+=300);
    }
    if (V7.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 7, value: 0});}, 100);
    }
    if (V8.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 8, value: 0});}, 100);
    }
    if (V83.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 83, value: 0});}, 100);
    }
    if (V11.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 11, value: 0});}, 100);
    }
    if (V9.lastValue == 1) {
        setTimeout(function(){ gladys.deviceType.exec({devicetype: 9, value: 0});}, 100);
    }
})();

Je souhaitais mettre des await devant les gladys.deviceType.exec mais 1) je ne sais pas si c’est nécéssaire, et 2) je ne sais pas pourquoi il refuse et me dis que ce n’est pas dans une fonction async. La fonction setTimeout m’empêche de le faire ? Est-il mieux de mettre des await pour gladys.script.exec(); ?
Pourrais-tu m’éclairer ? :wink:

PS : fonctionnement OK sans les await ici. Et j’utilise malheureusement énormément de fonctions setTimeout

EDIT : Solution ?
image


#16

En fait le await est juste un mot clé qui “bloque” le passage à la ligne suivante, (c’est pas exactement le terme vu qu’à l’intérieur le programme n’est pas bloqué, c’est asynchrone).

Dans tes setTimeout il n’y a pas de ligne suivante, donc await pas nécessaire.

Après, effectivement la solution c’est de faire une fonction async en mettant le mot clé async comme tu as trouvé :slight_smile: