Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. ioBroker Allgemein
    4. js-controller 4.0 jetzt im BETA/LATEST!

    NEWS

    • Monatsrückblick - April 2025

    • Minor js-controller 7.0.7 Update in latest repo

    • Save The Date: ioBroker@Smart Living Forum Solingen, 14.06.

    js-controller 4.0 jetzt im BETA/LATEST!

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

      @diginix Hm ... Was war denn in dem Zeitraum? Ist das ein Start oder zwischendrin? Ein Backup? Oder was ist da gewesen? Habe solche "Ausschläge" noch nie gesehen 🙂

      1 Reply Last reply Reply Quote 0
      • Diginix
        Diginix @AlCalzone last edited by

        @alcalzone sagte in js-controller 4.0 jetzt im BETA/LATEST!:

        @diginix sagte in js-controller 4.0 jetzt im BETA/LATEST!:

        iobroker start nach js-controller Update auf 4.0.12. Wobei die Ver. wahrs. egal ist. Aber der js-controller nimmt sich da fast 3min 2 GB RAM. Da ist klar warum der bei sonst <1GB freien RAM der VM vom OOM abgeschossen wurde.

        D.h. der Peak ist der Controller-Start? Wenn ja, magst du mir mal deine objects.jsonl, states.jsonl und iobroker.json schicken, dass ich das nachstellen kann? Schick dir nen Upload-Link per PN.

        Ja der peak war bei/ab "iobroker start" nach dem js-controller Update auf 4.0.12.

        Dateien sende ich dir.

        apollon77 1 Reply Last reply Reply Quote 1
        • apollon77
          apollon77 @Diginix last edited by

          @diginix Kannst Du denn Peak mit einem einfachen "neuen" Start reproduzieren?

          Diginix 1 Reply Last reply Reply Quote 0
          • H
            homecineplexx @apollon77 last edited by

            @apollon77 said in js-controller 4.0 jetzt im BETA/LATEST!:

            @homecineplexx sagte in js-controller 4.0 jetzt im BETA/LATEST!:

            -) 5386/2642

            Naja dann hast Du in der dritten ein Skript laufen was sehr viele "setState" oder andere Aktionen macht ... Wenn das so soll ist ja alles in Ordnung 🙂

            ich hab hier einfach viele solcher Skripte am laufen, die mir quasi einen Alias machen und bissl mehr noch.
            Vielleicht könnte man diese ja auch vereinfachen...?

            var preNameSpace = 'VirtualDevice.0.';
            
            //generic virtual device        
            function VirtualDevice(config) {
                //sanity check
                if (typeof config !== 'object' || typeof config.namespace !== 'string' || typeof config.name !== 'string' || typeof config.states !== 'object') {
                    log('sanity check failed, no device created', 'warn');
                    return;
                }
             
                this.config = config;
                this.namespace = preNameSpace + config.namespace + '.' + config.name;
                this.name = config.name;
             
                //create virtual device
                log('creating virtual device ' + this.namespace);
                this.createDevice(function () {
                    this.createStates(function () {
                        log('created virtual device ' + this.namespace);
                    }.bind(this));
                }.bind(this));
            }
             
            VirtualDevice.prototype.createDevice = function (callback) {
                log('creating object for device ' + this.namespace, 'debug');
                //create device object
                var obj = this.config.copy ? getObject(this.config.copy) : {common: {}, native: {}};
                delete obj.common.custom;
                if (typeof this.config.common === 'object') {
                    obj.common = Object.assign(obj.common, this.config.common);
                }
                if (typeof this.config.native === 'object') {
                    obj.native = Object.assign(obj.native, this.config.native);
                }
                extendObject(this.namespace, {
                    //type: "device",
                    type: "channel",
                    common: obj.common,
                    native: obj.native
                }, function (err) {
                    if (err) {
                        log('could not create virtual device: ' + this.namespace, 'warn');
                        return;
                    }
                    log('created object for device ' + this.namespace, 'debug');
                    if (typeof this.config.onCreate === 'function') {
                        this.config.onCreate(this, callback);
                    } else {
                        callback();
                    }
                }.bind(this));
            };
              
            VirtualDevice.prototype.createStates = function (callback) {
                "use strict";
                log('creating states for device ' + this.namespace, 'debug');
                var stateIds = Object.keys(this.config.states);
                log('creating states ' + JSON.stringify(stateIds), 'debug');
                var countCreated = 0;
                for (var i = 0; i < stateIds.length; i++) {
                    let stateId = stateIds[i];
                    this.normalizeState(stateId);
                    var id = this.namespace + '.' + stateId;
                    log('creating state ' + id, 'debug');
                    var obj = this.config.states[stateId].copy ? getObject(this.config.states[stateId].copy) : {
                        type: "state",
                        common: {},
                        native: {}
                    };
                    delete obj.common.custom;
                    if (typeof this.config.states[stateId].common === 'object') {
                        obj.common = Object.assign(obj.common, this.config.states[stateId].common);
                    }
                    if (typeof this.config.states[stateId].native === 'object') {
                        obj.native = Object.assign(obj.native, this.config.states[stateId].native);
                    }
            
            		setObject(id, obj, function(err, checkObj) {
            			if (err) {
                            log('skipping creation of state ' + id, 'debug');
                        } else {
                            log('created state ' + id, 'debug');
                        }
                        if (!err && checkObj) {
                            //setTimeout(function(){
                                this.connectState(stateId);
                                countCreated++;
                                if (countCreated >= stateIds.length) {
                                    log('created ' + countCreated + ' states for device ' + this.namespace, 'debug');
                                    callback();
                                }
            
                                var newId = checkObj.id;
                                var helper = newId.substr(newId.lastIndexOf('.') + 1, newId.length);
                                
                                var stateValueNew = this.config.states[helper].stateValue;
                                
                                if (stateValueNew !== undefined) {
                                    setStateDelayed(newId, stateValueNew, true, 1000);
                                    log('set default: ' + stateValueNew + ' for ' + newId);
                                }
                            //}.bind(this), 500);
                        }
            		}.bind(this)); 
                }
            };
             
            VirtualDevice.prototype.normalizeState = function (state) {
                log('normalizing state ' + state, 'debug');
                if (typeof this.config.states[state].read !== 'object') {
                    this.config.states[state].read = {};
                }
                if (typeof this.config.states[state].write !== 'object') {
                    this.config.states[state].write = {};
                }
             
                var readIds = Object.keys(this.config.states[state].read);
                for (var i = 0; i < readIds.length; i++) {
                    var readId = this.config.states[state].read[readIds[i]];
                    if (typeof readId.before !== 'function') {
                        this.config.states[state].read[readIds[i]].before = function (device, value, callback) {
                            callback();
                        };
                    }
                    if (typeof readId.after !== 'function') {
                        this.config.states[state].read[readIds[i]].after = function (device, value) {
                        };
                    }
                }
                var writeIds = Object.keys(this.config.states[state].write);
                for (i = 0; i < writeIds.length; i++) {
                    var writeId = this.config.states[state].write[writeIds[i]];
                    if (typeof writeId.before !== 'function') {
                        this.config.states[state].write[writeIds[i]].before = function (device, value, callback) {
                            callback()
                        };
                    }
                    if (typeof writeId.after !== 'function') {
                        this.config.states[state].write[writeIds[i]].after = function (device, value) {
                        };
                    }
                }
                log('normalized state ' + state, 'debug');
            };
             
            
            VirtualDevice.prototype.connectState = function (state) {
                setTimeout(function(){
                    log('connecting state ' + state, 'debug');
                    var id = this.namespace + '.' + state;
                
                    //subscribe to read ids
                    var readIds = Object.keys(this.config.states[state].read);
                    for (var i = 0; i < readIds.length; i++) {
                        if (readIds[i] === null || readIds[i] === undefined || readIds[i] === '') {
                            continue;
                        }
                        if (getState(readIds[i]).notExist === true) { //check if state exists
                            log('cannot connect to not existing state: ' + readIds[i], 'warn');
                            continue;
                        }
                        var readObj = this.config.states[state].read[readIds[i]];
                        var trigger = readObj.trigger || {change: 'any'};
                        trigger.ack = true;
                        trigger.id = readIds[i];
                        this.subRead(trigger, readObj, state);
                        log('connected ' + readIds[i] + ' to ' + id, 'debug');
                    }
                
                    //subscribe to this state and write to write ids
                    var writeIds = Object.keys(this.config.states[state].write);
                    var trigger = {id: this.namespace + '.' + state, change: 'any', ack: false};
            
                    on(trigger, function (obj) {
                        "use strict";
                        log('detected change of ' + state, 'debug');
                        for (var i = 0; i < writeIds.length; i++) {
                            let writeObj = this.config.states[state].write[writeIds[i]];
                            let val = this.convertValue(obj.state.val, writeObj.convert);
                            let writeId = writeIds[i];
                            log('executing function before for ' + writeId, 'debug');
                            writeObj.before(this, val, function (newVal, newDelay) {
                                if (newVal !== undefined && newVal !== null) val = newVal;
                                var delay = writeObj.delay;
                                if (newDelay !== undefined && newDelay !== null) delay = newDelay;
                                log(newVal + 'writing value ' + val + ' to ' + writeId + ' with delay ' + delay, 'debug');
                                setStateDelayed(writeId, val, false, delay || 0, true, function () {
                                    log('executing function after for ' + writeId, 'debug');
                                    writeObj.after(this, val);
                                }.bind(this));
                            }.bind(this));
                        }
                    }.bind(this));
            
                    log('connected ' + state + ' to ' + JSON.stringify(writeIds), 'debug');
                }.bind(this), 500);
            };
              
            VirtualDevice.prototype.subRead = function (trigger, readObj, state) {
                var func = function (obj) {
                    var val = this.convertValue(obj.state.val, readObj.convert);
             
                    log('executing function before for ' + trigger.id, 'debug');
                    readObj.before(this, val, function (newVal, newDelay) {
                        if (newVal !== undefined && newVal !== null) val = newVal;
                        if (newDelay !== undefined && newDelay !== null) writeObj.delay = newDelay;
                        log('reading value ' + val + ' to ' + this.namespace + '.' + state, 'debug');
                        setStateDelayed(this.namespace + '.' + state, val, true, readObj.delay || 0, true, function () {
                            log('executing function after for ' + trigger.id, 'debug');
                            readObj.after(this, val);
                        }.bind(this));
                    }.bind(this));
                }.bind(this);
                func({state: getState(trigger.id)});
                on(trigger, func);
            };
             
            VirtualDevice.prototype.convertValue = function (val, func) {
                if (typeof func !== 'function') {
                    return val;
                }
                return func(val);
            };
            
            var deviceId = 'Deckenlicht';
            var namespace = 'Ankleide';
            var path = preNameSpace + namespace + '.' + deviceId;
            
            new VirtualDevice({
                namespace: namespace,
                name: deviceId,
                states: {
                    'name': {
                        common: {name: 'name', role: 'text', type: 'string', desc: 'name', read: true, write: false, def: namespace + ' - ' + deviceId},
                        stateValue: namespace + ' - ' + deviceId
                    },
                    'isTelegramInfo': {
                        common: {name: 'TelegramInfo wird durch JavaScript gesetzt', role: 'state', type: 'boolean', desc: 'TelegramInfo', read: true, write: true, def: true},
                        stateValue: true
                    },
                    'isTelegramInfoSwitch': {
                        common: {name: 'TelegramInfo wird durch JavaScript gesetzt', role: 'state', type: 'boolean', desc: 'TelegramInfo', read: true, write: true, def: true},
                        stateValue: true
                    },
                    'switch': {
                        common: {name: 'switch', role: 'switch', type: 'boolean', desc: 'switch', def: false, read: true, write: true,
                            custom: {
                                'influxdb.0': {
                                    'enabled': true,
                                    'changesOnly': true,
                                    'debounce': 0,
                                    'maxLength': 10,
                                    'retention': 0,
                                    'changesRelogInterval': 30,
                                    'changesMinDelta': 0,
                                    'storageType': '',
                                    'aliasId': ''
                                }
                            }
                        },
                        read: {
                            'mqtt.0.shellies.shelly1-555EDB.relay.0': {
                                convert: function (val) {
                                    if (val == 'on') {
                                        val = true;
                                    } else {
                                        val = false;
                                    }
                                    return val;
                                },
                                trigger: setTimeout(function(){
                                            on({id:path + '.switch', change: 'ne'}, function (obj) {
                                                if (getState(path + '.isTelegramInfoSwitch').val === true) {
                                                    var value = obj.state.val;
                                                    var name = getState(path + '.name').val;
            
                                                    _sendLogToTelegram(_findCorrectEmoji(name + ' wurde ' + (value === true ? 'eingeschaltet.' : 'ausgeschaltet.')));
                                                } 
                                            })
                                        }, 500)
                            },
                        },
                        write: {
                            'mqtt.0.shellies.shelly1-555EDB.relay.0.command': {
                                convert: function (val) {
                                    if (val === true) {
                                        val ='on';
                                    } else {
                                        val = 'off';
                                    }
                                    return val;
                                },
                            },
                        }
                    },
                    'online': {
                        common: {name: 'online', role: 'variable', type: 'boolean', desc: 'online', read: true, write: false, def: false,
                            custom: {
                                'influxdb.0': {
                                    'enabled': true,
                                    'changesOnly': true,
                                    'debounce': 0,
                                    'maxLength': 10,
                                    'retention': 0,
                                    'changesRelogInterval': 30,
                                    'changesMinDelta': 0,
                                    'storageType': '',
                                    'aliasId': ''
                                }
                            }
                        },
                        read: {
                            'mqtt.0.shellies.shelly1-555EDB.online': {
                                trigger: setTimeout(function(){
                                        on({id:path + '.online', change: 'ne'}, function (obj) {
                                            var value = obj.state.val;
            
                                            if (value === false) {
                                                setState('AllOwnCreated.0.shelly.isWrongState', true);
                                            }
            
                                            if (getState(path + '.isTelegramInfo').val === true) {
                                                var name = getState(path + '.name').val;
            
                                                _sendLogToTelegram(_findCorrectEmoji('OnlineStatus: ' + name + ' ist ' + (value === true ? 'wieder' : 'nicht') + ' erreichbar.'));
                                            } 
                                        })
                                    }, 500)
                            },
                        },
                        write: {}
                    },
                    'command': {
                        common: {name: 'command', role: 'variable',  type: 'string', desc: 'command', read: true, write: true, def: ''},
                        read: {
                            'mqtt.0.shellies.shelly1-555EDB.command': {},
                        },
                        write: {
                            'mqtt.0.shellies.shelly1-555EDB.command': {
                            },
                        }
                    },
                    'announce': {
                        common: {name: 'announce', role: 'variable',  type: 'string', desc: 'announce', read: true, write: false, def: ''},
                        read: {
                            'mqtt.0.shellies.shelly1-555EDB.announce': {
                                convert: function (val) {
                                   var jsonValue = JSON.parse(val);
                                   
                                    calculateJson(jsonValue, 'Info');
            
                                    return val;
                                },
                            },
                        },
                    },
                    'info': {
                        common: {name: 'info', role: 'variable',  type: 'string', desc: 'info', read: true, write: false, def: ''},
                        read: {
                            'mqtt.0.shellies.shelly1-555EDB.info': {},
                        },
                    },      
                }
            }); 
            
            function calculateJson(jsonValue, subFolder) {
                for (var key in jsonValue) {
                    if (jsonValue.hasOwnProperty(key)) {
                        try {  
                            var jsonNewValue = JSON.parse(jsonValue[key]);  
            
                            calculateJson(jsonNewValue)
                        } catch (e) {
                            if (typeof jsonValue[key] == 'object') {
                                for (var item in jsonValue[key]) {
                                    //var commonType = getCommonType(item);
                                    var commonType = null;
                                    doCreateStates(path + '.' + subFolder +'.' + item, item, jsonValue[key][item], commonType) 
                                }
                            } else {
                                doCreateStates(path + '.' + subFolder + '.' + key, key, jsonValue[key])    
                            }    
                        }
                    }
                }
            }
            
            function doCreateStates(newObject, name, value, commonType) {
                var obj = getObject(newObject);
            
                if (commonType == undefined) {
                    commonType = {'name': name, 'role': 'state', 'type': 'string', desc: name, read: true, write: false, def: ''};
                }
            
                if (commonType['type'] == 'number') {
                    
                } else {
                    value = '' + value;
                }
            
            	if (!obj) {
            		setObject(newObject, {
            			type: 'state',
            			common: commonType,
            			native: {}
            		}, function(err, obj) {
            			if (!err && obj) {
            				console.log('Object for ' + obj.id + ' created');
                            setState(newObject, value, true);
            			}
            		});
            	} else {
                    setState(newObject, value, true);    
                }
            
                if (name == 'LWT') {
                    setTimeout(function() {
                        on({id:newObject, change: 'ne'}, function (obj) {
                            if (getState(path + '.isTelegramInfo').val === true) {
                                var value = obj.state.val;
                                var name = getState(path + '.name').val;
            
                                _sendLogToTelegram(_findCorrectEmoji(name + ' wurde neu gestartet. Grund: ' + value));
                            } 
                        })
                    }, 500)    
                }
            }
            
            
            
            
            apollon77 1 Reply Last reply Reply Quote 0
            • apollon77
              apollon77 @homecineplexx last edited by

              @homecineplexx naja wenn duhier mit einem JavaScript sehr viele "States mirrorst" dann ist das ja alles "Ok" dasdie Zahl so hoch ist - was willst Du da noch optimieren 🙂 (Ausser es auf echte Aliases umzubauen, dann brauchst Du solche Skripte nicht) ...

              H 1 Reply Last reply Reply Quote 0
              • Diginix
                Diginix @apollon77 last edited by

                @apollon77 Vermute mal ja. Das Update war ja nur der Auslöser für den Neustart. Ich warte mal was @AlCalzone zu meinen Dateien sagt und dann kann ich das auch noch mal testen ohne Updates oder sonstige Änderungen.

                apollon77 1 Reply Last reply Reply Quote 0
                • apollon77
                  apollon77 @Diginix last edited by

                  @diginix mach doch parallel ... also schick Ihm die files und mach mal stop und start und schau ob es wieder passiert ... Wäre denke auch für @AlCalzone ne interessante info

                  Diginix 1 Reply Last reply Reply Quote 0
                  • H
                    homecineplexx @apollon77 last edited by

                    @apollon77 said in js-controller 4.0 jetzt im BETA/LATEST!:

                    Ausser es auf echte Aliases umzubauen, dann brauchst Du solche Skripte nicht

                    geb ich dir absolut recht, allerdings lass ich dort auch zusätzlich gleich gewisse Datenpunkte in die Influxdb schreiben und zusätzlich überwachen. ich weiß nicht ob ich das mit Alias kann?

                    apollon77 1 Reply Last reply Reply Quote 0
                    • apollon77
                      apollon77 @homecineplexx last edited by

                      @homecineplexx Auch wenn ziemlich Off-Topic hier: Für Aliase kannst du auch Influxdb logging aktivieren und für "überwachen" wirst Du ggf eigene Skripte brauchen. Lange Rede ... Wenn die Skripte das tun was Du sagst und da "so viel Changes" zusammenkommen wie Du oben geschrieben hast ist doch erstmal alles ok ... Wichtig ist zu unterscheiden ob so soll oder da ein Skript Amok läuft

                      1 Reply Last reply Reply Quote 0
                      • Diginix
                        Diginix @apollon77 last edited by

                        @apollon77 Hm, ein iob stop mit anschließendem Reboot des Servers, also komplette Proxmox Host (gab Kernel Updates) und somit ja dann im Anschluss auch wieder ein iob start hat keinerlei Peak erzeugt. Nun wird nat. der RAM vom js-c über history erfasst und der Adapter muss natürlich erstmal laufen. Was ja aber gestern auch funktionierte.

                        Daher habe ich direkt noch mal ein iob stop, ps auxww | grep "io.", iob status, iob start gemacht.
                        "Leider" auch ohne Auffälligkeiten.

                        f1f8efc6-9e2d-41d9-9061-a1f4883343f8-image.png

                        Aber ich vermute, dass genau der Controller Peak von gestern auch in der Vergangenheit seit 4.x für die OOM Kills bei mir ursächlich war. Was den Peak selbst auslöst, ist leider weiterhin unbekannt.
                        Wird nach einem js-controller Update noch etwas gemacht was bei einem Neustart der selben Controller Version dann nicht mehr geschieht?

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

                          @diginix sagte in js-controller 4.0 jetzt im BETA/LATEST!:

                          Wird nach einem js-controller Update noch etwas gemacht was bei einem Neustart der selben Controller Version dann nicht mehr geschieht?

                          iobroker setup first vielleicht @apollon77 ?

                          foxriver76 apollon77 2 Replies Last reply Reply Quote 0
                          • foxriver76
                            foxriver76 Developer @AlCalzone last edited by

                            @alcalzone Ja, wird ausgeführt und darin werden paar Objekte aufgeräumt, sichergestellt, dass systemSecret, certs da sind + Sets Migration.

                            Habe jetzt nicht viel gelesen, aber Sets Migration sind approx. n calls gegen die DB, wobei n die Anzahl an Objekten ist.

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

                              Hmm also mit den Dateien, die ich von @Diginix bekommen hab, startet der Controller-Prozess problemlos und dümpelt dann bei so 300 MB RAM. Ich probier jetzt mal nur setup first zu debuggen.

                              1 Reply Last reply Reply Quote 0
                              • apollon77
                                apollon77 @AlCalzone last edited by apollon77

                                @alcalzone hab ich auch schon überlegt aber am Ende werden von CLI Kommandos keine Reporting Werte geliefert! Also wenn die daten so in den system-host.NAME.x States stehen können SIe nur von einem "normal laufenden controller" kommen.

                                Auch ein "erster Start nach Update" ist an sich nicht unterschiedlich zu jedem anderen Start

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

                                  Ich bin neugierig und wollte es doch nochmal bestätigt haben. setup first mit den Datenbanken ging bei mir auch max. auf 350 MB RAM.

                                  Diginix 1 Reply Last reply Reply Quote 0
                                  • Diginix
                                    Diginix @AlCalzone last edited by Diginix

                                    @alcalzone Tja, dann muss es vorerst als mehrmals vorkommender Einzelfall abgehakt werden. 😉
                                    Ich lasse das RAM Logging mal für den js-controller weiterlaufen mit Vorhaltezeit von 3 Tagen.
                                    Aber das wird zur Ursachenforschung wahrs. nicht viel beitragen.

                                    Johannes Bauerstatter 1 Reply Last reply Reply Quote 0
                                    • Johannes Bauerstatter
                                      Johannes Bauerstatter @Diginix last edited by

                                      Hallo mit Typ: js-controller 4.0.12 funktioniert der Shelly Adapter nicht mehr. Kann ich den js-controller auch auf eine bestimmte Version downgraden? Mit Version 4.0.9 hat noch alles funktioniert.

                                      JohGre amg_666 2 Replies Last reply Reply Quote 0
                                      • JohGre
                                        JohGre @Johannes Bauerstatter last edited by

                                        @johannes-bauerstatter sagte in js-controller 4.0 jetzt im BETA/LATEST!:

                                        js-controller 4.0.12 funktioniert der Shelly Adapter nicht mehr

                                        Kann ich so nicht bestätigen: Shelly-Adapter 5.2.0 läuft bei mir

                                        Diginix 1 Reply Last reply Reply Quote 1
                                        • amg_666
                                          amg_666 @Johannes Bauerstatter last edited by

                                          @johannes-bauerstatter sagte in js-controller 4.0 jetzt im BETA/LATEST!:

                                          js-controller 4.0.12 funktioniert der Shelly Adapter nicht mehr

                                          bei mir läuft der shelly 5.2.0 ohne Probleme mit js 4.0.12

                                          Johannes Bauerstatter 1 Reply Last reply Reply Quote 0
                                          • Johannes Bauerstatter
                                            Johannes Bauerstatter @amg_666 last edited by

                                            @amg_666 welche Firmware habt ihr in den Shellies? Letzte Frage weil falscher Threads.

                                            da_Woody amg_666 2 Replies 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

                                            792
                                            Online

                                            31.6k
                                            Users

                                            79.4k
                                            Topics

                                            1.3m
                                            Posts

                                            70
                                            747
                                            145054
                                            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