Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. ioBroker Allgemein
    4. [Vorschlag] Core-API und Javascript-Adapter => Promises

    NEWS

    • Wir empfehlen: Node.js 22.x

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker goes Matter ... Matter Adapter in Stable

    [Vorschlag] Core-API und Javascript-Adapter => Promises

    This topic has been deleted. Only users with topic management privileges can see it.
    • Bluefox
      Bluefox last edited by

      Die Promises sind nicht schlecht nur aus Erfahrung weiß ich, dass es Probleme zwischen 0.12, 4, 6 gibt.

      Es gibt bluebird, q, native promises und die unterscheiden sich.

      Manchmal darf man

      getState('aaa')
      .then(function(result){})
      .fail(function (e) {
      });
      

      schreiben.

      Manchmal

      getState('aaa')
      .then(function(result){})
      .fail(function (e) {
      }).catch(function () {
      });
      
      getState('aaa')
      .then(function(result){})
      .fail(function (e) {
      }).catch(function () {
      });
      

      manchmal

      getState('aaa')
      .then(function(result){})
      .fail(function (e) {
      }).fin(function () {
          // close files, database connections, stop servers, conclude tests
      });
      

      Und wenn so was wie

      getState('aaa')
      .then(function(result){ 
          throw new Error('error');
      });
      
      

      dann wirst du NIE dein Exception sehen und wirst SEHR lange debuggen, wo der Fehler ist.

      Wie gesagt, wenn jemand die gut findet, habe ich nichts dagegen.

      Nur sehe ich immer noch mehr Problemen als Nützlichkeit dabei. Ihr habt einfach noch nie ein problem mit Native => Q => Bluebird => throw new Error() gesucht… Ich schon.

      1 Reply Last reply Reply Quote 0
      • AlCalzone
        AlCalzone Developer last edited by

        @Bluefox:

        getState('aaa')
        .then(function(result){})
        .fail(function (e) {
        }).fin(function () {
            // close files, database connections, stop servers, conclude tests
        });
        ```` `  
        

        fail/finally sind soweit ich weiß nicht im ECMAScript-Standard, nur then/catch werden unterstützt. Die ganzen Libraries können idR. mehr, welche da am sinnvollsten ist, weiß ich nicht. Ich wäre mit native schon glücklich.

        @Bluefox:

        Und wenn so was wie

        getState('aaa')
        .then(function(result){ 
            throw new Error('error');
        });
        
        

        dann wirst du NIE dein Exception sehen und wirst SEHR lange debuggen, wo der Fehler ist. `
        Dieser Code müsste an entsprechender Stelle im JS-Adapter/adapter.js eingefügt werden, um genau diese versteckten Fehler in die Konsole zu leiten.

        // Unbehandelte Fehler tracen
        process.on('unhandledRejection', r => {
            console.log("unhandled promise rejection: " + r);
        });
        
        
        1 Reply Last reply Reply Quote 0
        • AlCalzone
          AlCalzone Developer last edited by

          @fsjoke:

          Alcazone,

          ich verwende auch ausschließlich promises, in den Adaptern und im Javascriopt-Adapter bei scripts.

          […]

          Dort definiere ich von Zeile 20-~83 einige Funktionen mit denen ich:

          aus jeder Funtion […] eine Funktion machen kann die eine promise zurückgibt `
          Jap, sowas habe ich auch, wäre halt praktisch, wenn das von Hause aus gehen würde.

          @fsjoke:

          Willst du Promises in Javascript oder in Adaptern verwenden? `
          Primär in JavaScript, ich habe nur vor kurzem einen Thread bezüglich Adapter-Entwicklung gelesen, bei dem mir aufgefallen ist, dass getState dort asynchron ist. Daher würde sich das anbieten.

          1 Reply Last reply Reply Quote 0
          • Bluefox
            Bluefox last edited by

            @AlCalzone:

            @Bluefox:

            getState('aaa')
            .then(function(result){})
            .fail(function (e) {
            }).fin(function () {
                // close files, database connections, stop servers, conclude tests
            });
            ```` `  
            

            fail/finally sind soweit ich weiß nicht im ECMAScript-Standard, nur then/catch werden unterstützt. Die ganzen Libraries können idR. mehr, welche da am sinnvollsten ist, weiß ich nicht. Ich wäre mit native schon glücklich.

            @Bluefox:

            Und wenn so was wie

            getState('aaa')
            .then(function(result){ 
                throw new Error('error');
            });
            
            

            dann wirst du NIE dein Exception sehen und wirst SEHR lange debuggen, wo der Fehler ist. `
            Dieser Code müsste an entsprechender Stelle im JS-Adapter/adapter.js eingefügt werden, um genau diese versteckten Fehler in die Konsole zu leiten.

            // Unbehandelte Fehler tracen
            process.on('unhandledRejection', r => {
                console.log("unhandled promise rejection: " + r);
            });
            
            ```` `  
            

            Das geht nur wenn du native promises verwendest. Und was wenn 0.12 + bluebird?

            0.12 will ich ende April rausschmeißen und dann kann man über so was nachdenken.

            1 Reply Last reply Reply Quote 0
            • frankjoke
              frankjoke last edited by

              Bluefox,

              ja, ich verwende nur die native nodejs promises und seit 4 gibts da keine Probleme. Vesuche generell keine Zusatzmodule einzusetzten da diese zusätzlichen Arbeistspeicher und Zeit (zumindest beim Laden) beanspruchen. Ich hasse Module die wegen zwei Abfragen z.B. lodash brauchen.

              Habe deswegen (mittels den eigenen Promises-Routinen) auch z.B. das Async-package aus allen Adaptern und Scripten entfernt und versuche ausschließlich in nodejs-integrierte Module zu verwenden. Deshalb hab ich mir auch mein pGet geschrieben um ohne dem request-Modul auszukommen das leider rausgeflogen ist.

              Für den JS-Adapter wäre es wirklich nicht schlecht in die Sandbox einige Promisified-Funktionen einzubinden.

              Es wäre auch nicht schlecht die Sandbox unter 'use strict'; laufen zu lassen da dies wesentlich mehr Programmierfehler aufdeckt.

              Und zusätzlich wäre es toll diese 'Global script' in eine require-Funktion umzuwandeln. Also ich kann global scripts definieren die ich mit 'require' im script importiere anstatt alle Globals die aktiv sind vorne anzuhängen.

              1 Reply Last reply Reply Quote 0
              • AlCalzone
                AlCalzone Developer last edited by

                @Bluefox:

                Das geht nur wenn du native promises verwendest. […]

                0.12 will ich ende April rausschmeißen und dann kann man über so was nachdenken. `

                Klingt nach einem Deal!

                @fsjoke:

                Und zusätzlich wäre es toll diese 'Global script' in eine require-Funktion umzuwandeln. Also ich kann global scripts definieren die ich mit 'require' im script importiere anstatt alle Globals die aktiv sind vorne anzuhängen. `
                Gute Idee. Ist aber vermutlich ein breaking change für alle Nutzer der global scripts. Vielleicht stattdessen ein weiterer Ordner "Module"?

                1 Reply Last reply Reply Quote 0
                • frankjoke
                  frankjoke last edited by

                  Ja, Module gingen auch, ist nur wirklich blöd dass die globalen scripts immer angehängt werden, auch bei separaten Instanzen.

                  Ich habe seit ich meine StateMaschine verwende Gott sei Dank auf 2 Scripts (und eine Instanz) reduziert und auch node-red rausgeschmissen.

                  Aber beim Testen von globalen scripts stört es sehr dass alles neu gestartet wird.

                  1 Reply Last reply Reply Quote 0
                  • htrecksler
                    htrecksler Forum Testing last edited by

                    > Also ich kann global scripts definieren die ich mit 'require' im script importiere anstatt alle Globals die aktiv sind vorne anzuhängen

                    Ist das ein großer Aufwand das zu tun? Ich nutzte sehr gerne die "global scripts" (zumindest am Anfang), aber irgendwann wurde mir das zu unübersichtlich.

                    Also habe ich mir in einem Texteditor quasi eine Funktionssammlung angelegt aus der ich einzelne Funktionen in ein Script "kopiere" (händisch)

                    Mich hat irgendwie gestört, das immer das gesamte globale Script vorangestellt wurde.

                    Es wäre toll wenn man einzelne Funktionsblöcke definieren und diese bei Bedarf in das Script laden könnte.

                    1 Reply Last reply Reply Quote 0
                    • AlCalzone
                      AlCalzone Developer last edited by

                      Um hierauf mal zurück zu kommen. Folgende Funktionen der Adapter-Klasse habe ich aktuell als Promises gekapselt:

                      adapter.objects.getObjectList
                      adapter.getForeignObject     
                      adapter.setForeignObject     
                      adapter.getForeignObjects    
                      adapter.getForeignState      
                      adapter.getObject            
                      adapter.setObject            
                      adapter.getState             
                      adapter.setState             
                      adapter.createState          
                      

                      extendObject wäre in dieser Liste vermutlich auch gut aufgehoben.

                      1 Reply Last reply Reply Quote 0
                      • frankjoke
                        frankjoke last edited by

                        Hallo mitsammen!

                        Verwende ausschließlich Promises in meinen Adaptern, und dabei die internen ab node 4.3 hatte ich nie Probleme.

                        Um die Adapterentwicklung zu vereinfachen hab ich mir ein Skelett erstellt welche die meisten verwendeten Prozeduren in Promises umwandelt und auch einige angern (wie http/https get, exec, …).

                        Es schaut ca so aus:

                        ! ````
                        "use strict";
                        const util = require('util');
                        const http = require('http');
                        const https = require('https');
                        const exec = require('child_process').exec;
                        const querystring = require('querystring');
                        const assert = require('assert');
                        ! function _O(obj, level) { return util.inspect(obj, false, level || 2, false).replace(/\n/g, ' '); }
                        function _N(fun) { return setTimeout.apply(null, [fun, 0].concat(Array.prototype.slice.call(arguments, 1))); } // move fun to next schedule keeping arguments
                        function _D(l, v) { adapter.log.debug(l); return v === undefined ? l : v; } // version for final adapter, use below for testing
                        //function _D(str, val) { adapter.log.info(debug: ${str}); return val !== undefined ? val : str; } // Write debug message in log, optionally return 2nd argument
                        function _I(l, v) { adapter.log.info(l); return v === undefined ? l : v; }
                        function _W(l, v) { adapter.log.warn(l); return v === undefined ? l : v; }
                        function _T(i) {
                        var t = typeof i; if (t === 'object') {
                        if (Array.isArray(i)) t = 'array';
                        else if (i instanceof RegExp) t = 'regexp';
                        else if (i === null) t = 'null';
                        } else if (t === 'number' && isNaN(i)) t = 'NaN';
                        return t;
                        }
                        ! const P = {
                        res: (what) => Promise.resolve(what),
                        rej: (what) => Promise.reject(what),
                        wait: (time, arg) => new Promise(res => setTimeout(res, time, arg)),
                        ! series: (obj, promfn, delay) => { // fun gets(item) and returns a promise
                        assert(typeof promfn === 'function', 'series(obj,promfn,delay) error: promfn is not a function!');
                        delay = delay || 0;
                        let p = Promise.resolve();
                        const nv = [],
                        f = (k) => p = p.then(() => promfn(k).then(res => P.wait(delay, nv.push(res))));
                        for (let item of obj)
                        f(item);
                        return p.then(() => nv);
                        },
                        ! c2p: (f) => {
                        assert(typeof f === 'function', 'c2p (f) error: f is not a function!');
                        if (!f)
                        throw new Error(f = null in c2pP definition!);
                        return function() {
                        const args = Array.prototype.slice.call(arguments);
                        return new Promise((res, rej) => {
                        args.push((err, result) => (err && _N(rej, err)) || _N(res, result));
                        f.apply(this, args);
                        });
                        }
                        },
                        ! c1p: (f) => {
                        assert(typeof f === 'function', 'c1p (f) error: f is not a function!');
                        return function() {
                        const args = Array.prototype.slice.call(arguments);
                        return new Promise((res, rej) => {
                        args.push((result) => _N(res, result));
                        f.apply(this, args);
                        });
                        };
                        },
                        ! retry: (nretry, fn, arg) => {
                        return fn(arg).catch(err => {
                        if (nretry <= 0)
                        throw err;
                        return P.retry(nretry - 1, fn,arg);
                        });
                        },

                        repeat: (nretry, fn, arg) => {
                            return fn(arg).then(() => Promise.reject()).catch(err => { 
                                if (nretry <= 0)
                                    return Promise.resolve();
                                return P.repeat(nretry - 1, fn,arg); 
                            });
                        },
                        

                        ! exec: (command) => {
                        const istest = command.startsWith('!');
                        return new Promise((resolve, reject) => {
                        exec(istest ? command.slice(1) : command, (error, stdout, stderr) => {
                        if (istest && error) {
                        error[stderr] = stderr;
                        return reject(error);
                        }
                        resolve(stdout);
                        });
                        });
                        },
                        ! get: (url,retry) => { // get a web page either with http or https and return a promise for the data, could be done also with request but request is now an external package and http/https are part of nodejs.
                        const fun = typeof url === 'string' && url.trim().toLowerCase().startsWith('https') ||
                        url.protocol == 'https' ? https.get : http.get;
                        return (new Promise((resolve,reject)=> {
                        fun(url, (res) => {
                        const statusCode = res.statusCode;
                        const contentType = res.headers['content-type'];
                        if (statusCode !== 200) {
                        const error = new Error(Request Failed. Status Code: ${statusCode});
                        res.resume(); // consume response data to free up memory
                        return reject(error);
                        }
                        res.setEncoding('utf8');
                        var rawData = '';
                        res.on('data', (chunk) => rawData += chunk);
                        res.on('end', () => resolve(rawData));
                        }).on('error', (e) => reject(e));
                        })).catch(err => {
                        if (!retry) reject(err);
                        return P.wait(100,retry -1).then(a => P.get(url,a));
                        });
                        },
                        ! initAdapter: () => {
                        P.getObjectList = P.c2p(adapter.objects.getObjectList),
                        P.getForeignObject = P.c2p(adapter.getForeignObject),
                        P.setForeignObject = P.c2p(adapter.setForeignObject),
                        P.getForeignObjects = P.c2p(adapter.getForeignObjects),
                        P.getForeignState = P.c2p(adapter.getForeignState),
                        P.getState = P.c2p(adapter.getState),
                        P.setState = P.c2p(adapter.setState),
                        P.getObject = P.c2p(adapter.getObject),
                        P.deleteState = P.c2p(adapter.deleteState),
                        P.delObject = P.c2p(adapter.delObject),
                        P.setObject = P.c2p(adapter.setObject),
                        P.createState = P.c2p(adapter.createState),
                        P.extendObject = P.c2p(adapter.extendObject);
                        }

                        }

                        ! var isStopping = false;
                        var scanTimer = null;
                        ! function stop(dostop) {
                        isStopping = true;
                        if (scanTimer)
                        clearInterval(scanTimer);
                        scanTimer = null;
                        _W('Adapter disconnected and stopped');
                        }
                        ! adapter.on('message', obj => processMessage(obj));
                        ! adapter.on('ready', () => main(P.initAdapter()));
                        ! adapter.on('unload', () => stop(false));
                        ! function processMessage(obj) {
                        if (obj && obj.command) {
                        _D(process Message ${_O(obj)});
                        switch (obj.command) {
                        case 'ping': {
                        // Try to connect to mqtt broker
                        if (obj.callback && obj.message) {
                        ping.probe(obj.message, { log: adapter.log.debug }, function (err, result) {
                        adapter.sendTo(obj.from, obj.command, res, obj.callback);
                        });
                        }
                        break;
                        }
                        }
                        }
                        adapter.getMessage(function (err, obj) {
                        if (obj) {
                        processMessage(obj);
                        }
                        });
                        }
                        ! ````

                        P.c2p erzeugt eine Promisifierte Version einer Funktion die fun(…, callback(error, data)) also ein callback mit error == null erwartet.

                        Bei callbacks ohne error nehm ich c1p .

                        repeat, rety und series sind konstrukte die andere Promises hintereinander ausführen.

                        exec und get verwend ich oft in allen Adaptern.

                        Beim adapter.ready wird main() aufgerufen und vorher die ioBroker adapterfunktionen mit c2p erstellt da einige von uhnen noch nicht bereit sind wenn der Adapter nicht gestartet ist.

                        Damit brauch ich nur die 2 Zeilen einfügen um utils und den Adapter zu laden und kann dann mit dem Content loslegen.

                        1 Reply Last reply Reply Quote 0
                        • AlCalzone
                          AlCalzone Developer last edited by

                          Bin inzwischen auch hingegangen und ähnlich wie du im ready-Callback das Adapter-Objekt um promisifizierte Funktionen, farbigen Log, etc. erweitert, siehe https://github.com/AlCalzone/iobroker.t … /global.ts

                          Gleichzeitig nutze ich diesen Import um das Adapter-Objekt in eingebundenen (projektinternen) Modulen verfügbar zu machen ohne jedesmal die Variable zu übergeben.

                          1 Reply Last reply Reply Quote 0
                          • frankjoke
                            frankjoke last edited by

                            Ahh, du bist schon einen Schritt weiter: Typescript!

                            Ich habe bei meinen neuesten Adapter meine defaults etwas geändert und in ein Objekt konzentriert:

                            ! ```
                            const A = { // my Adapter object encapsulating all my default adapter variables/functions and Promises isStopping: false, scanDelay: 5 * 60 * 1000, // in ms = 5 min scanTimer: null, ! stop: (dostop) => { A.isStopping = true; if (A.scanTimer) clearInterval(A.scanTimer); A.scanTimer = null; if (adapter && adapter.log && adapter.log.warn) A.W(Adapter disconnected and stopped with (${dostop})); if(dostop) { A.E("Adapter will exit in lates 2 sec!"); setTimeout(process.exit,2000,55); } }, ! res: (what) => Promise.resolve(what), rej: (what) => Promise.reject(what), wait: (time, arg) => new Promise(res => setTimeout(res, time, arg)), ! O: (obj, level) => util.inspect(obj, false, level || 2, false).replace(/\n/g, ' '), ! // function _J(str) { try { return JSON.parse(str); } catch (e) { return {'error':'JSON Parse Error of:'+str}}} N: (fun) => setTimeout.apply(null, [fun, 0].concat(Array.prototype.slice.call(arguments, 1))), // move fun to next schedule keeping arguments D: (l, v) => (adapter.log.debug(l), v === undefined ? l : v), // D: (str, val) => (adapter.log.info(debug: ${str}), val !== undefined ? val : str), // Write debug message in log, optionally return 2nd argument I: (l, v) => (adapter.log.info(l), v === undefined ? l : v), W: (l, v) => (adapter.log.warn(l), v === undefined ? l : v), E: (l, v) => (adapter.log.error(l), v === undefined ? l : v), T: (i) => { var t = typeof i; if (t === 'object') { if (Array.isArray(i)) t = 'array'; else if (i instanceof RegExp) t = 'regexp'; else if (i === null) t = 'null'; } else if (t === 'number' && isNaN(i)) t = 'NaN'; return t; }, ! series: (obj, promfn, delay) => { // fun gets(item) and returns a promise assert(typeof promfn === 'function', 'series(obj,promfn,delay) error: promfn is not a function!'); delay = parseInt(delay); let p = Promise.resolve(); const nv = [], f = delay > 0 ? (k) => p = p.then(() => promfn(k).then(res => A.wait(delay, nv.push(res)))) : (k) => p = p.then(() => promfn(k)); for (let item of obj) f(item); return p.then(() => nv); }, ! c2p: (f) => { assert(typeof f === 'function', 'c2p (f) error: f is not a function!'); if (!f) throw new Error(f = null in c2pP definition!); return function () { const args = Array.prototype.slice.call(arguments); return new Promise((res, rej) => { args.push((err, result) => (err && rej(err)) || res(result)); f.apply(this, args); }); } }, ! c1p: (f) => { assert(typeof f === 'function', 'c1p (f) error: f is not a function!'); return function () { const args = Array.prototype.slice.call(arguments); return new Promise((res, rej) => { args.push((result) => res(result)); f.apply(this, args); }); }; }, ! c1pe: (f) => { // one parameter != null = error assert(typeof f === 'function', 'c1pe (f) error: f is not a function!'); return function () { const args = Array.prototype.slice.call(arguments); return new Promise((res, rej) => { args.push((result) => !result ? res(result) : rej(result)); f.apply(this, args); }); }; }, ! retry: (nretry, fn, arg) => { assert(typeof fn === 'function', 'retry (,fn,) error: fn is not a function!'); return fn(arg).catch(err => { if (nretry <= 0) throw err; return A.retry(nretry - 1, fn, arg); }); }, ! repeat: (nretry, fn, arg) => { assert(typeof fn === 'function', 'repeat (,fn,) error: fn is not a function!'); return fn(arg).then(() => Promise.reject()).catch(err => { if (nretry <= 0) return Promise.resolve(); return A.repeat(nretry - 1, fn, arg); }); }, ! exec: (command) => { assert(typeof fn === 'string', 'exec (fn) error: fn is not a string!'); const istest = command.startsWith('!'); return new Promise((resolve, reject) => { exec(istest ? command.slice(1) : command, (error, stdout, stderr) => { if (istest && error) { error[stderr] = stderr; return reject(error); } resolve(stdout); }); }); }, ! get: (url, retry) => { // get a web page either with http or https and return a promise for the data, could be done also with request but request is now an external package and http/https are part of nodejs. const fun = typeof url === 'string' && url.trim().toLowerCase().startsWith('https') || url.protocol == 'https' ? https.get : http.get; return (new Promise((resolve, reject) => { fun(url, (res) => { const statusCode = res.statusCode; const contentType = res.headers['content-type']; if (statusCode !== 200) { const error = new Error(Request Failed. Status Code: ${statusCode}); res.resume(); // consume response data to free up memory return reject(error); } res.setEncoding('utf8'); var rawData = ''; res.on('data', (chunk) => rawData += chunk); res.on('end', () => resolve(rawData)); }).on('error', (e) => reject(e)); })).catch(err => { if (!retry) reject(err); return A.wait(100, retry - 1).then(a => A.get(url, a)); }); }, ! initAdapter: () => { A.ains = adapter.name + '.' + adapter.instance; A.ain = A.ains + '.'; A.D(Adapter ${A.ains} starting.); A.getObjectList = A.c2p(adapter.objects.getObjectList), A.getForeignObject = A.c2p(adapter.getForeignObject), A.setForeignObject = A.c2p(adapter.setForeignObject), A.getForeignObjects = A.c2p(adapter.getForeignObjects), A.getForeignState = A.c2p(adapter.getForeignState), A.getState = A.c2p(adapter.getState), A.setState = A.c2p(adapter.setState), A.getObject = A.c2p(adapter.getObject), A.deleteState = (id) => A.c1pe(adapter.deleteState)(id).catch(res => res == 'Not exists' ? A.res() : A.rej(res)), A.delState = (id, opt) => A.c1pe(adapter.delState)(id, opt).catch(res => res == 'Not exists' ? A.res() : A.rej(res)), A.delObject = (id, opt) => A.c1pe(adapter.delObject)(id, opt).catch(res => res == 'Not exists' ? A.res() : A.rej(res)), A.removeState = (id, opt) => A.delState(id, opt).then(() => A.delObject(id, opt)), A.setObject = A.c2p(adapter.setObject), A.createState = A.c2p(adapter.createState), A.extendObject = A.c2p(adapter.extendObject); A.states = {}; (!adapter.config.forceinit ? A.res({ rows: [] }) : A.getObjectList({ startkey: A.ain, endkey: A.ain + '\u9999' })) .then(res => A.series(res.rows, (i) => A.removeState(A.D('deleteState: ' + i.doc.common.name, i.doc.common.name)), 2)) .then(res => res, err => A.E('err from A.series: ' + err)) .then(() => A.getObjectList({ include_docs: true })) .then(res => { res = res && res.rows ? res.rows : []; A.objects = {}; for (let i of res) A.objects[i.doc._id] = i.doc; if (A.objects['system.config'] && A.objects['system.config'].common.language) adapter.config.lang = A.objects['system.config'].common.language; if (A.objects['system.config'] && A.objects['system.config'].common.latitude) { adapter.config.latitude = parseFloat(A.objects['system.config'].common.latitude); adapter.config.longitude = parseFloat(A.objects['system.config'].common.longitude); } return res.length; }, err => A.E('err from getObjectList: ' + err, 'no')) .then(len => { A.D(${adapter.name} received ${len} objects with config ${Object.keys(adapter.config)}); // A.D('System Objects: '+A.O(A.objects,5)) adapter.subscribeStates('*'); return main(); }).catch(err => A.W(Error in adapter.ready: ${err})); }, ! changeState: function (id, value, ack, always) { assert(typeof id === 'string', 'changeState (id,,,) error: id is not a string!'); always = always === undefined ? false : !!always; ack = ack === undefined ? true : !!ack; return A.getState(id) .then(st => st && !always && st.val == value && st.ack == ack ? A.res() : A.setState(id, value, ack)) .catch(err => A.W(Error in A.setState(${id},${value},${ack}): ${err}, A.setState(id, value, ack))); }, ! makeState: function (ido, value, ack) { ack = ack === undefined || !!ack; let id = ido; if (typeof id === 'string') ido = id.endsWith('Percent') ? { unit: "%" } : {}; else if (typeof id.id === 'string') { id = id.id; } else return Promise.reject(A.W(Invalid makeState id: ${A.O(id)})); if (A.states[id]) return A.changeState(id, value, ack); // A.D(Make State ${id} and set value to:${A.O(value)} ack:${ack}) ///TC var st = { common: { name: id, // You can add here some description read: true, write: false, state: 'state', role: 'value', type: typeof value }, type: 'state', _id: id }; ! for (let i in ido) if (i != 'id' && i != 'val') st.common[i] = ido[i]; ! return A.extendObject(id, st, null) .then(x => A.states[id] = x) .then(() => st.common.state == 'state' ? A.changeState(id, value, ack) : A.res()) .catch(err => A.D(MS ${A.O(err)}, id)); }, ! processMessage: (obj) => { if (obj && obj.command) { A.D(process Message ${A.O(obj)}); switch (obj.command) { case 'ping': // Try to connect to mqtt broker if (obj.callback && obj.message) { ping.probe(obj.message, { log: adapter.log.debug }, function (err, result) { adapter.sendTo(obj.from, obj.command, res, obj.callback); }); } break; case 'send': // e.g. send email or pushover or whatever A.D(A.ains + ' send command from message'); if (obj.callback) // Send response in callback if required adapter.sendTo(obj.from, obj.command, 'Message received', obj.callback); break; } } adapter.getMessage((err, obj) => obj ? A.processMessage(obj) : null); } } ! adapter.on('message', obj => A.processMessage(obj)); ! adapter.on('ready', () => A.initAdapter()); ! adapter.on('unload', () => A.stop(false));
                            ! Da ist das main() nur noch 20 Zeilen lang!
                            ! Beim debuggen bin ich draufgekommen dass ich eine eigene Promisify für die Funktionen brauchen die nur ein (err) Argument im callback verwenden:
                            ! deleteState, delObject, delState.
                            ! Hab auch alle drei geändert um den 'Not exist'-Fehler nicht als reject zu sehen.[/i][/i]

                            1 Reply Last reply Reply Quote 0
                            • AlCalzone
                              AlCalzone Developer last edited by

                              @fsjoke:

                              Ahh, du bist schon einen Schritt weiter: Typescript! `
                              Ja: https://github.com/ioBroker/ioBroker.template-ts

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post

                              Support us

                              ioBroker
                              Community Adapters
                              Donate
                              FAQ Cloud / IOT
                              HowTo: Node.js-Update
                              HowTo: Backup/Restore
                              Downloads
                              BLOG

                              828
                              Online

                              32.0k
                              Users

                              80.4k
                              Topics

                              1.3m
                              Posts

                              5
                              17
                              3813
                              Loading More Posts
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes
                              Reply
                              • Reply as topic
                              Log in to reply
                              Community
                              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                              The ioBroker Community 2014-2023
                              logo