Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Seit dem Javascript Adapter Update –-Fehlermeldung

NEWS

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    23
    1
    1.3k

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    9.3k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    14
    1
    2.5k

Seit dem Javascript Adapter Update –-Fehlermeldung

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
7 Beiträge 5 Kommentatoren 1.6k Aufrufe
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • A Offline
    A Offline
    abuzze
    schrieb am zuletzt editiert von
    #1

    Hallo

    Ich habe gestern beim Javascript Adapter ein Update gemacht und bekomme beim starten des Scripts folgende Fehlermeldung:

    –------------------------------------------------------------------------------------------------------------------------------

    14:38:34.369 [error] javascript.0 SyntaxError: Unexpected end of JSON input at Object.parse (native) at dpAbfrageAlexaAnlegen (script.js.common.Alexa.Skript1(1):207:32) at IncomingMessage. (script.js.common.Alexa.Skript1(1):176:81) at emitNone (events.js:91:20) at IncomingMessage.emit (events.js:185:7) at endReadableNT (_stream_readable.js:974:12) at _combinedTickCallback (internal/process/next_tick.js:80:11) at process._tickCallback (internal/process/next_tick.js:104:9)

    14:38:34.486 [error] Caught by controller[0]: at dpAbfrageAlexaAnlegen (script.js.common.Alexa.Skript1(1):207:32)

    14:38:34.487 [error] Caught by controller[0]: at IncomingMessage. (script.js.common.Alexa.Skript1(1):176:81)

    –-------------------------------------------------------------------------------------------------------------------------------

    Kann jemand mir weiter helfen ? Vor dem Update war alles gut.

    1 Antwort Letzte Antwort
    0
    • BuZZyB Offline
      BuZZyB Offline
      BuZZy
      schrieb am zuletzt editiert von
      #2

      Da stimmt was mit dem Json input nicht.. Steht doch da.. :roll: :lol:

      Wäre hilfreich wenn du das entsprechende Script zeigen würdest..

      Gruß

      1 Antwort Letzte Antwort
      0
      • A Offline
        A Offline
        abuzze
        schrieb am zuletzt editiert von
        #3

        @BuZZy:

        Da stimmt was mit dem Json input nicht.. Steht doch da.. :roll: :lol:

        Wäre hilfreich wenn du das entsprechende Script zeigen würdest..

        Gruß `

        Hallo

        also hier ist das Script welches ermöglicht Alexa anzusteuern.

        ! ```
        `// Alexa mit Javaskript in ioBroker steuern
        // Skript arbeitet unabhängig vom Cloud Adapter
        // Version: v0.3.1
        // -----------------------------------------------------------------------------
        // alexaCommand("arbeitszimmer","volume",70); // Alle Anwendungen
        // alexaCommand("arbeitszimmer","pause"); // Radio, Spotify, Hörbücher
        // alexaCommand("arbeitszimmer","play"); // Radio, Spotify, Hörbücher
        // alexaCommand("arbeitszimmer","next"); // z.B. Spotify: nächstes Lied
        // alexaCommand("arbeitszimmer","previous"); // z.B. Spotify: vorheriges Lied
        // alexaCommand("arbeitszimmer","forward"); // z.B. Hörbücher: 30 Sekunden vor
        // alexaCommand("arbeitszimmer","rewind"); // z.B. Hörbücher: 30 Sekunden zurück
        // alexaCommand("arbeitszimmer","shuffle",true); // z.B Amazon Music, Shuffle ein in der aktuellen Playlist
        // alexaCommand("arbeitszimmer","shuffle",false); // z.B Amazon Music, Shuffle aus in der aktuellen Playlist
        // alexaCommand("arbeitszimmer","radio",true); // schaltet den Default tunein Radiosender an
        // alexaCommand("arbeitszimmer","radio",false); // setzt Radio auf Pause
        // alexaCommand("arbeitszimmer","tunein","s100198"); // setzt tunein Radio auf "s100198" (Einslive)

        // EINRICHTUNG:

        // 1. cURL extrahieren, siehe
        // https://www.gehrig.info/alexa/Alexa.html
        //
        // benötigt wird:
        // je Gerät: deviceType, deviceSerialNumber
        // einmalig: csrf, cookie
        //
        // Der Cookie muss aus dem Trace mit tunein entnommen werden, damit er sowohl mit den Kommandos,
        // als auch mit der Radistation funktioniert. Es ist ein sehr langer String
        // alles von: x-amzn-dat-gui-client
        // bis alles vor dem nächsten -H

        // ----------------------------------------
        // Infos und Resourcen zum Skript:
        // Webseiten/URLs Request mit Fehlerbehandlung, siehe:
        // http://forum.iobroker.net/viewtopic.php?f=21&t=4259&p=40890&hilit=request#p40880
        // Alexa Steuerskripte:
        // https://github.com/thorsten-gehrig/alexa-remote-control

        // ---------------------------------------
        // Tunein Radiosender:
        // http://tunein.com/radio/Antenne-Düsseldorf-1042-s25772/
        // s25772 -> Antenne Düsseldorf

        // Liste einiger Sender:
        // s25772 -> Antenne Düsseldorf
        // s100198 -> Einslive
        // s100183 -> WDR2 Rheinland
        // s8007 -> Hitradio Ö3

        // ---------------------------------------
        // Changelog:

        // 0.3.1 Fehlerkorrekturen
        // 0.3.0 alle createState() mit Callback
        // 0.2.0 Redesigne. Ale bekannten Alexa-Geräte werden nun ausgelesen. Keine manuelle Pflege nötig.
        // (nur noch der Cookie und csrf müssen ausgelesen werden)
        // 0.1.2 mediaOwnerCustomerId vom Skriptbereich in den individuellen Konfigurationsbereich verlegt

        // ---------------------------------------
        // TODOs:

        // GET: fragt aktuellen Titel ab:
        // path: '/api/np/queue?deviceSerialNumber=xxxxxxxx&deviceType=xxxxxxxxx',

        // GET: fragt viele Statusinfo ab (Titel, Status, Volume, Muted, ...):
        // path: '/api/media/state?deviceSerialNumber=xxxxxxxxxxxxx&deviceType=xxxxxxxxxx',

        // prüfen: Authentifizierung mit User/PW möglich? Erhaltenen Cookie dann für die weitere Verwendung speichern

        // prüfen: Statusänderungen abonieren?

        // Alexa Objekt als Sicherung in DP ablegen

        // deviceSerialNumber aus dem Array Echos auch als Datenpunkt anlegen

        // ---------------------------------------
        // bekannte Probleme:

        // ein ungültiger Cookie lässt das Skript unter Umständen abstürzen

        // Skriptverhalten:
        var logOn = true; // Skript Logausgabe ein- (true) / ausschalten (false). Fehler werden unabhängig von dieser Einstellung ausgegeben.
        var forecreation = false; // true: Datenpunkte werden überschrieben (wenn z.B. Bezeichnungen geändert wurden)

        var pfad = "alexa_device_command" +"."; // Pfad im Javascript-Adapter unter dem die Geräte angelegt werden sollen

        var defaultRadiostation = "s25111"; // Radioeins vom rbb - Default Radiostation für den Radio an Button.

        // Individuelle Daten, per Chrome Debug ermitteln, siehe Link in der Beschreibung oben:

        var csrf = 'xxxxxxxxxxx';
        // cookie gilt für alle Devices
        var cookie = 'xxxxcookie';

        // Liste der bekannten Devicetypen, Geräte mit bekannten DeviceType und "anlegen":true werden mit Steuermöglichkeit mit steuerbaren Datenpunkten angelegt
        // hier muss nur was angepasst werden, wenn für andere Geräte auch Steuerdatenpunkte angelegt werden sollen
        // oder wenn es ein Geröte gibt, welches hier nicht gepflegt ist
        var knownDeviceType = {
        "A3S5BH2HU6VAYF": {"device":"Echo Dot 2.Gen", "anlegen": true},
        "AB72C64C86AW2": {"device":"Echo ", "anlegen": true},
        "A10A33FOX2NUBK": {"device":"Spot ", "anlegen": true},
        "A2E0SNTXJVT7WK": {"device":"Fire TV V1", "anlegen": false},
        "ADVBD696BHNV5": {"device":"Fire TV Stick V1", "anlegen": false},
        "A2T0P32DY3F7VB": {"device":"echosim.io", "anlegen": false},
        "AILBSA2LNTOYL": {"device":"reverb App", "anlegen": false}

        !
        };

        // -----------------------------------------------------------------------------
        // ------------ Skript, ab hier nichts ändern --------------
        // -----------------------------------------------------------------------------

        var devicePfad = pfad + "devices" + "."; // Pfad unter dem die zu steuernden Geräte angelegt werden
        var otherDevicePfad = pfad + "other_devices" + "."; // Pfad unter dem die

        var mediaOwnerCustomerId; // CUSTOMERID wird aus der Geräteliste ausgelesen
        var alexaDeviceObj = {}; // globales Objekt mit den Devices von Alexa abgefragt
        var echos = {}; // globales Objekt echos mit allen zu steuernden Echos (echos = {"arbeitszimmer":{"deviceSerialNumber": "XXXXXXX", "deviceType":"A3S5BH2HU6VAYF"},...)

        var https = require('https'); // Node Module https verwenden

        var ok = true;

        function setOptions(path,method) { // setzt die Options für den http/https Request
        var options = {
        host: 'layla.amazon.de',
        path: path,
        method: method,
        timeout:10000,
        headers: {
        'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
        'Content-Type': 'text/plain',
        'csrf' : csrf,
        'Cookie' : cookie
        }
        };
        return options;
        }

        function httpsReqGet(path,callback) {
        if(logOn) log("Abfrage " + path + " an Alexa gesendet");
        options = setOptions(path,"GET");
        log("hallo");
        var req = https.get(options, function getDevices(res) {
        log("Du");
        if(logOn) log('STATUS: ' + res.statusCode) + ": " + statusCode(res.statusCode); // Statuscode
        if(logOn) log('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
        // Buffer the body entirely for processing as a whole.
        var bodyChunks = [];
        var chunkLine = 0;

            res.on('data', function(chunk) {
                chunkLine = chunkLine + 1;
                // Hier können die einzelnen Zeilen verarbeitet werden...
                //if(logOn)  log("Zeilennummer: " + chunkLine+ " ,Inhalt: " +  chunk);
                bodyChunks.push(chunk);
        
            }).on('end', function() {
                //if(logOn) log("ARRAY mit den einzelnen Zeilen: " + bodyChunks);
                //if(logOn) log("ARRAY Länge: " + bodyChunks.length);
                var body = Buffer.concat(bodyChunks);
                // ...und/oder das Gesamtergebnis (body).
                if(!body) log("keine Daten erhalten","warn");
                if(logOn) log('BODY: ' + body);
        
                if(callback !== undefined && typeof callback === 'function') return callback(null, body, dpAnlegen);
                ok = false;
                log("kein gültiger Callback angegeben","warn");
                return log(body,"warn");
            });
        
        });
        
        req.on('error', function(e) { // Fehler abfangen
            log('ERROR: ' + e.message,"warn");
            if(callback !== undefined && typeof callback === 'function') return callback(e.message, null);
            log("keinen gültigen Callback gefunden","warn");
            ok = false;
            return log("error: " + e.message,"warn");
        });
        req.end();
        

        }

        function dpAbfrageAlexaAnlegen (err,result,callback) {
        if (err) {
        log("Abfrage der bekannten Devices bei Alexa mit Fehler","warn");
        log("Error: " + err);
        ok = false;
        return log("Automatisches Anlegen/Aktualisieren von Datenpunkten mit Fehler abgebrochen","warn");
        }
        //TODO: Test (im if darüber: wenn error, dann prüfen, ob alte Daten vorhanden sind und diese laden: alexaDeviceObj & mediaOwnerCustomerId)
        //log("###############: "+ getState(pfad+"_alexaDeviceObj").val);

        if(!result) return log("Es konnten keine Daten ermittelt werden! Cookie richtig?","warn");
        if(logOn) log(result);
        alexaDeviceObj      = JSON.parse(result);
        createState(pfad + "_alexaDeviceObj",     JSON.stringify(alexaDeviceObj),  true,  {name:"Object mit allen Devices",   type:"string",  role:"value"});
        var numberOfDevices     = alexaDeviceObj.devices.length;
        if(logOn) log("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices);
        
        if (numberOfDevices < 1) {
            ok = false;
            return log("Error: Skript konnte keine Geräte abfragen","warn");
        }
        
        mediaOwnerCustomerId = alexaDeviceObj.devices[0].deviceOwnerCustomerId; // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben
        createState(pfad + "_mediaOwnerCustomerId",     mediaOwnerCustomerId,  forecreation,  {name:"Individuelle Kunden ID",   type:"string",  role:"value"});
        
        var device;
        var dpName;
        for(var i = 0; i < numberOfDevices; i++) {
            device = alexaDeviceObj.devices[i].accountName;       
            dpName = clearName(alexaDeviceObj.devices[i].accountName);
            log("Gerät " + i + ": " + device+" - Datenpunktname: " + dpName);
            alexaDeviceObj.devices[i].dpName = dpName;
        
            if(typeof(knownDeviceType[alexaDeviceObj.devices[i].deviceType]) != "undefined") {
                alexaDeviceObj.devices[i].anlegen = knownDeviceType[alexaDeviceObj.devices[i].deviceType].anlegen;
            } else {
                alexaDeviceObj.devices[i].anlegen = false;
                log(device + " : Gerätetyp ("+alexaDeviceObj.devices[i].deviceType+") unbekannt. Keine Steuerungsmöglichkeiten angelegt","warn");
            }
            //log(alexaDeviceObj.devices[i].anlegen);
        }
        
        if(logOn) log("deviceOwnerCustomerId: " + mediaOwnerCustomerId);
        
        if(callback !== undefined && typeof callback === 'function') {
            return null, callback(); // !!! weiter zu dpAnlegen
        }
        log("kein Callback");
        return log("Skriptfehler: error: kein Callback","warn");
        

        }

        function createStates(arr, func, cb) {
        var doneCounter = 0;
        arr.forEach(function alleDpBearbeiten(obj) {
        func(obj.name, obj.initialValue, obj.forceCreation, obj.common, function () {
        doneCounter += 1;
        //if(logOn) log(doneCounter+": " + obj.name+" mit Wert: " + obj.initialValue + " ("+obj.common.type+") angelegt");
        if (doneCounter === arr.length) {
        cb(); // mit der Funktion (callback) geht es weiter, wenn alles erledigt ist
        }
        });
        });
        }

        function createStateObj(arr,name,initialValue,forceCreation,common){
        var obj = {
        "name":name,
        "initialValue":initialValue,
        "forceCreation":forceCreation,
        "common":common
        };
        return arr.push(obj);
        }

        function createStatesReady() {
        log("--- Alexa Kommandos - Datenpunkte angelegt ---");
        //setOn();
        setTimeout(setOn, 3000);
        }

        function dpAnlegen() {
        var dfSt = defaultRadiostation;
        var fc = forecreation; //forecreation;
        var deviceType,essid,macAddress,swVersion,deviceTypeTxt,capabilities;
        var echo;
        var dpArr = [];
        // for (var echo in echos) {
        for(var i = 0; i < alexaDeviceObj.devices.length; i++) {
        var pfad = otherDevicePfad;
        echo = alexaDeviceObj.devices[i].dpName;
        if(alexaDeviceObj.devices[i].anlegen) {
        pfad = devicePfad;
        echos[echo] = {"deviceType":alexaDeviceObj.devices[i].deviceType,"deviceSerialNumber":alexaDeviceObj.devices[i].serialNumber};
        createStateObj(dpArr,pfad + echo +".volume", 40, false, {name:"Volume (0-100)", type:"number", role:"control.value"});
        createStateObj(dpArr,pfad + echo +".pause", false, fc, {name:"Pause", type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".play", false, fc, {name:"Play", type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".next", false, fc, {name:"Next (nächster Titel)", type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".previous", false, fc, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".forward", false, fc, {name:"Forward (Hörbuch 30 Sekunden vor)", type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".rewind", false, fc, {name:"Rewind (Hörbuch 30 Sekunden zurück)",type:"boolean", role:"button"});
        createStateObj(dpArr,pfad + echo +".shuffle", false, fc, {name:"Shuffel an/aus (true/false)", type:"boolean", role:"switch"});
        createStateObj(dpArr,pfad + echo +".Last_Status","init", fc, {name:"Letzter Status", type:"string", role:"value"});
        createStateObj(dpArr,pfad + echo +".radio", false, fc, {name:"Default Radiostation an/aus", type:"boolean", role:"switch"});
        createStateObj(dpArr,pfad + echo +".tunein", dfSt, fc, {name:"tunein Radiosenderkennung", type:"string", role:"control.value"});
        }
        essid = alexaDeviceObj.devices[i].essid;
        macAddress = alexaDeviceObj.devices[i].macAddress;
        swVersion = alexaDeviceObj.devices[i].softwareVersion;
        deviceTypeTxt = deviceTypeStr(alexaDeviceObj.devices[i].deviceType);
        deviceType = alexaDeviceObj.devices[i].deviceType;
        capabilities = JSON.stringify(alexaDeviceObj.devices[i].capabilities);

                createStateObj(dpArr,pfad + echo +"._info.device_type_str",  deviceTypeTxt,  true,   {name:"Amazon Echo Typ",            type:"string",      role:"value"});
                createStateObj(dpArr,pfad + echo +"._info.device_type",      deviceType,     fc,     {name:"Amazon Echo deviceType",     type:"string",      role:"value"});
                createStateObj(dpArr,pfad + echo +"._info.essid",            essid,          true,   {name:"SSID des WLANs",             type:"string",      role:"value"});
                createStateObj(dpArr,pfad + echo +"._info.macAddress",       macAddress,     fc,     {name:"MAc-Adresse des Echos",      type:"string",      role:"value"});
                createStateObj(dpArr,pfad + echo +"._info.softwareVersion",  swVersion,      true,   {name:"Softwareversion des Echos",  type:"string",      role:"value"});
                createStateObj(dpArr,pfad + echo +"._info.capabilities",     capabilities,   true,   {name:"Fähigkeiten des Echos",      type:"string",      role:"value"});
        }
        
        if(logOn) log("Anzahl der anzulegenden Datenpunkte: " + dpArr.length);
        createStates(dpArr, createState, createStatesReady);
        

        }

        function clearName(name){ // Sonderzeichen gegen Unterstrich ersetzen
        name = umlaut(name);
        name = name.replace(/\W/g,"_");
        return name;
        }

        function httpsReqCmd(device,data) { // schickt an ein Alexa-Gerät (device) ein Kommando (data) per https-Request / Daten im Body
        if(logOn) log("Kommando: " + data);
        // Seriennummer und Gerätetyp anhand der Device-Bezeichnung ermitteln
        var deviceSerialNumber = echos[device].deviceSerialNumber;
        var deviceType = echos[device].deviceType;
        var path = '/api/np/command?deviceSerialNumber='+deviceSerialNumber+'&deviceType='+deviceType;
        if(JSON.parse(data).type == "tunein") {
        var guideId = JSON.parse(data).station;
        // path setzt eine Radiostation
        path = '/api/tunein/queue-and-play?deviceSerialNumber='+deviceSerialNumber+'&deviceType='+deviceType+'&guideId='+guideId+'&contentType=station&callSign=&mediaOwnerCustomerId='+mediaOwnerCustomerId;
        }
        var options = setOptions(path,"POST");

        // https Request für Alexa Kommandos:
        var req = https.request(options, function(res) {
        
            if(logOn) log("Geräteyp: " + deviceTypeStr(deviceType)); // Name des Alexa/Amazon Gerätetyps als String ausgeben
            setState(devicePfad + device +".Last_Status",res.statusCode.toString()+" " + statusCode(res.statusCode));
            if(res.statusCode != 200) {
                log("Negative Rückmeldung von Alexa: " + res.statusCode + ": " + statusCode(res.statusCode),"warn");
                log("Gesendetes Kommando: " + data,"warn");
            } else {
                log('STATUS: ' + res.statusCode + ": " + statusCode(res.statusCode)); // Statuscode
            }
            if(logOn || res.statusCode != 200) log('HEADERS: ' + JSON.stringify(res.headers), (res.statusCode != 200 ? "warn" : "info")); // Header (Rückmeldung vom Webserver)
        });
        
        req.on('error', function(e) { // Fehler abfangen
            log('ERROR: ' + e.message,"warn");
        });
        
        if(logOn) log("Data to request body: " + data);
        // write data to request body
        if(data) req.write(data);
        req.end();
        

        }

        function umlaut(str) {
        return str
        .replace(/ |À|Å|Ã/g, "A")
        .replace(/â|à|å|ã/g, "a")
        .replace(/Ä/g, "AE")
        .replace(/ä/g, "ae")
        .replace(/Ç/g, "C")
        .replace(/ç/g, "c")
        .replace(/É|Ê|È|Ë/g, "E")
        .replace(/é|ê|è|ë/g, "e")
        .replace(/Ó|Ô|Ò|Õ|Ø/g, "O")
        .replace(/ó|ô|ò|õ/g, "o")
        .replace(/Ö/g, "OE")
        .replace(/ö/g, "oe")
        .replace(/Š/g, "S")
        .replace(/š/g, "s")
        .replace(/ß/g, "ss")
        .replace(/Ú|Û|Ù/g, "U")
        .replace(/ú|û|ù/g, "u")
        .replace(/Ü/g, "UE")
        .replace(/ü/g, "ue")
        .replace(/Ý|Ÿ/g, "Y")
        .replace(/ý|ÿ/g, "y")
        .replace(/Ž/g, "Z")
        .replace(/ž/, "z");
        }

        function statusCode(status) { // gibt zum http-Status eine Rückmeldung als String
        if(status === 0) return "** Daten unvollständig ** (csrf fehlt/falsch? Cookie falsch?)";
        if(status == 200) return "** OK ";
        if(status == 302) return "
        Found (Moved Temporarily) ** (Cookie abgelaufen?)";
        if(status == 401) return "** Unauthorized ** (Cookie nicht richtig gesetzt?)";
        if(status == 403) return "** Forbidden ** (Kombination Cookie, deviceType, Seriennummer richtig?)";
        if(status == 404) return "** Not Found ** (Kommando im Kontext des Geräts sinnvoll?)";
        if(status == 500) return "** Internal Server Error** (ggf. Kommando im falschen Kontext verwendet?)";
        return "Fehler";
        }

        function deviceTypeStr(deviceType){ // Anhand der Amazon Device Kennung wird ein String mit dem Typ als Namen zurückgeliefert
        if(!knownDeviceType[deviceType] || knownDeviceType[deviceType] === undefined) return "Gerät unbekannt";
        return knownDeviceType[deviceType].device;
        }

        function alexaCommand(device,cmd,parameter) { // Fürt ein Kommando (cmd) an ein Alexa-Gerät (device) mit optionalen Parameter (parameter) aus
        var data;
        if(!echos[device] || echos[device] === undefined) return log("Kein gültiger Raum","warn");
        if(logOn) log("Kommando für: " + device);
        switch (cmd) {

        case "volume":
            if(!parameter ||parameter === null){
                log("Alexa Volume: keine Lautstärke angegeben. Parameter fehlt.","warn");
                break;
            }
            parameter = parseInt(parameter);
            if(parameter < 0) {
                parameter = 0;
                log("Alexa Volume: ungültige Lautsträke angegeben (<0). Auf 0 gesetzt.","warn");
            }
            if(parameter > 100) {
                parameter = 100;
                log("Alexa Volume: ungültige Lautsträke angegeben (>100). Auf 1000 gesetzt.","warn");
            }
        
            httpsReqCmd(device,'{"type":"VolumeLevelCommand","volumeLevel":'+parameter+'}');
            break;
        
        case "pause":
            httpsReqCmd(device,'{"type":"PauseCommand"}');
            break;
        
        case "play":
            httpsReqCmd(device,'{"type":"PlayCommand"}');
            break;
        
        case "next":
            httpsReqCmd(device,'{"type":"NextCommand"}');
            break;
        
        case "previous":
            httpsReqCmd(device,'{"type":"PreviousCommand"}');
            break;
        
        case "forward":
            httpsReqCmd('{"type":"ForwardCommand"}');
            break;
        
        case "rewind":
            httpsReqCmd(device,'{"type":"RewindCommand"}');
            break;
        
        case "shuffle":
            if(parameter === null){
                log("Alexa Shuffle: kein true/false angegeben. Auf true gesetzt.","warn");
                parameter = true;
            }
        
            httpsReqCmd(device,'{"type":"ShuffleCommand","shuffle":'+parameter+'}');
            break;
        
        case "tunein":
            httpsReqCmd(device,'{"type":"tunein","station":"'+parameter+'"}');
            break;
        
        default:
            log("Kein bekanntes Kommando angegeben: "+cmd,"warn");
            break;
        }
        

        }

        // Subscriptions
        // -----------------------------------------------------------------------------

        function setOn() {
        var reg = new RegExp("^javascript\."+instance+"\." + devicePfad.replace('.', '\.') + ".*\.(volume|pause|play|next|forward|rewind|shuffle|tunein|radio|previous)");
        on({"id":reg , "change": "any"}, function (obj) {
        var objArr = obj.id.match(/(^.+).(.+).(.+)$/, ""); //Aufteilung in Pfad + Device + CMD
        var device = objArr[2];
        var cmd = objArr[3];
        if(logOn) log("Device: " + device+", Kommando: " + cmd);

            switch (cmd) {
               case "radio":
                    if(obj.state.val) {
                        // default Radiostation einschalten
                        setState(devicePfad + device +".tunein",defaultRadiostation);
                    return;
                    } else {
                        // Musik auf Pause.
                        setState(devicePfad + device +".pause",true);
                        return;
                    }
                    break;
        
                // Buttons, true zum auslösen. Werden danach wieder auf flase gesetzt
                case "pause":
                case "play":
                case "next":
                case "forward":
                case "rewind":
                case "previous": 
                    if(getState(obj.id).val) setState(obj.id,false);    // Button wieder auf false zurücksetzen, wenn er true war
                    if(obj.state.val) alexaCommand(device,cmd,true);    // Kommando war ein true -> Kommando ausführen
                    break;
        
                // Switches oder Wert
                case "shuffle": 
                case "volume": 
                case "tunein": 
                    alexaCommand(device,cmd,obj.state.val);
                    break;
        
                default:
                    log("Kommando << "+cmd+" >> im Skript nicht behandelt","warn");
                    break;
            }
        
        });
        log("--- Subscriptions angelegt ---");
        

        }

        onStop(function skriptStop () {
        if (req) {
        req.end();
        }

        log("**** Skript wurde gestoppt ****");
        

        }, 2000 /ms/);

        // main
        // -----------------------------------------------------------------------------
        function main() {
        //alexaCommand("arbeitszimmer","pause");
        if (ok) {
        log("--- Alexa Kommandos - Skript initalisiert und bereit ---");
        } else {
        log("--- Skript konnte nicht sauber initalisiert werden ---","warn");
        }
        }

        // Start Skript:
        // -----------------------------------------------------------------------------

        log("--- Alexa Kommandos - Skript gestartet ---");
        if(forecreation) log("Forcecreation ist eingeschaltet. Wenn nicht mehr benötigt, bitte im Skript auf false setzen","warn");
        httpsReqGet('/api/devices/device',dpAbfrageAlexaAnlegen); // fragt bei Alexa die Devices ab und legt die Datenpunkte und dann die Subscriptions an
        setTimeout(main, 7000); // startet main()`
        Aber wie gesagt vor dem Update lief es[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]

        1 Antwort Letzte Antwort
        0
        • T Offline
          T Offline
          tempestas
          schrieb am zuletzt editiert von
          #4

          ich habe nicht aktualisiert, aber in dem Thread glaube ich ähnliche Fehler gepostet. Wahrscheinlich habe ich das Skript erst implementiert, als ich schon einen aktuellen JS Adapter hatte.

          host.iobrokerNUC   2018-01-20 10:36:10.397   error   instance system.adapter.javascript.0 terminated with code 6 (uncaught exception)
          host.iobrokerNUC   2018-01-20 10:36:10.397   error   Caught by controller[0]: at process._tickCallback (internal/process/next_tick.js:104:9)
          host.iobrokerNUC   2018-01-20 10:36:10.397   error   Caught by controller[0]: at _combinedTickCallback (internal/process/next_tick.js:80:11)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at endReadableNT (_stream_readable.js:974:12)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at IncomingMessage.emit (events.js:185:7)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at emitNone (events.js:91:20)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at IncomingMessage. (script.js.common.Amazon.Alexa:212:81)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at dpAbfrageAlexaAnlegen (script.js.common.Amazon.Alexa:243:32)
          host.iobrokerNUC   2018-01-20 10:36:10.396   error   Caught by controller[0]: at Object.parse (native)
          host.iobrokerNUC   2018-01-20 10:36:10.395   error   Caught by controller[0]: SyntaxError: Unexpected end of JSON input
          javascript.0   2018-01-20 10:36:08.954   error   SyntaxError: Unexpected end of JSON input at Object.parse (native) at dpAbfrageAlexaAnlegen (script.js.common.Amazon.Alexa:243:32) at IncomingMessage. (script.js.common.Amazon.A
          javascript.0   2018-01-20 10:36:08.954   error   uncaught exception: Unexpected end of JSON input
          

          <size="85">ioBroker | 21 Adapter | Ubuntu Server | intel NUC | Homematic CCU2 | Hue | Osram Lightify| Sonos | 2x Instar Cam | Samsung Tab A 2016 im Holzrahmen| 3x Echo dot | 1x Echo | Neato Botvac D5</size>

          1 Antwort Letzte Antwort
          0
          • M Offline
            M Offline
            MyMeyer
            schrieb am zuletzt editiert von
            #5

            Und was war hier jetzt die Lösung ?

            MyMeyer

            >>> Hardware: Intel I5 mit ****Debian ProxMox OS: Debian **** <<< >>> Network with UniFi <<<
            >>> HomeMatic CCU-2 (Wired und Funk) / Philips HUE / Echo.DOT / Echo.SHOW / Xiaomi Smart-Home / Xiaomi Robot Vacuum Cleaner / Synology DS 918+ / Shelly 1&2 <<<

            1 Antwort Letzte Antwort
            0
            • apollon77A Offline
              apollon77A Offline
              apollon77
              schrieb am zuletzt editiert von
              #6

              In dem Fall war das JSON was jemand mit "JSON.parse" parsen wollte ungültig und wirf daher diese exception.

              Wäre meine Vermutung.

              Da fehlt Fehlerbehandlung

              Beitrag hat geholfen? Votet rechts unten im Beitrag :-) https://paypal.me/Apollon77 / https://github.com/sponsors/Apollon77

              • Debug-Log für Instanz einschalten? Admin -> Instanzen -> Expertenmodus -> Instanz aufklappen - Loglevel ändern
              • Logfiles auf Platte /opt/iobroker/log/… nutzen, Admin schneidet Zeilen ab
              1 Antwort Letzte Antwort
              0
              • M Offline
                M Offline
                MyMeyer
                schrieb am zuletzt editiert von
                #7

                Hi…mein Problem das ich noch nicht genau weiß wie die Fehlermeldung und Script lesen soll !

                Gibt es dazu eine Anleitung. Ständig Fragen nervt. :roll: Wie es ja auch lernen....

                Hier mein Script dazu:

                ! // AlexaControl
                ! //
                ! // Version: v0.1.6
                ! // Author: Hauke
                ! // Dank an ruhr70 dessen Skript als Vorlage diente
                ! // http://forum.iobroker.net/viewtopic.php?f=37&t=6035
                ! // und Stefan.Franke, dessen Skript den Login per Cookie ermöglicht
                ! // http://forum.iobroker.net/viewtopic.php … gOn#p98493
                ! // Changelog:
                ! // v.0.1.6 Fehler behoben: Cannot use 'in' operator to search for 'provider' in undefined
                ! // v.0.1.5 Dummy-Objekte, falls Alexa {"message":null} antwortet, weil das Device derzeit nicht aktiv ist
                ! // v.0.1.4 Spielzeit und Titellänge werden nun im 2-Sekunden-Takt berechnet
                ! // v.0.1.3 WiFi ESSID / MAC werden ausgelesen
                ! // v.0.1.2 Playlists
                ! // v.0.1.1 History
                ! // v.0.1.0 erste brauchbare Version
                ! // ----------------------------------------------------------------------------------------------------
                ! // Settings:
                ! // ----------------------------------------------------------------------------------------------------
                ! // Loglevel kann folgenden Wert haben: debug, info, warn, error, none
                ! var logLevel = 'info';
                ! // true: Datenpunkte werden überschrieben (wenn z.B. Bezeichnungen geändert wurden)
                ! var forceCreation = true;
                ! // Pfad im Javascript-Adapter unter dem die Geräte angelegt werden sollen bei "Alexa" wird daraus z.B.: javascript.0.Alexa
                ! var pfad = "AlexaControl";
                ! // Hier die Datenpunkti mit dem Cookie und CSRF aus dem Script von Stefan.Franke
                ! var idCookie = "javascript.0.productive.alexalogon.cookie";
                ! var idCsrf = "javascript.0.productive.alexalogon.csrf";
                ! // Einslive - Default Radiostation für den Radio an Button.
                ! var defaultRadiostation = "s24885";
                ! // Jede Minute History auslesen? Wert im üblichen Unix Crontab-Stil
                ! // Manuell jeder Zeit per Button möglich.
                ! var updateHistoryScheduler = "* * * * ";
                ! // Wie oft Playlists automatisch auslesen? Wert im üblichen Unix Crontab-Stil
                ! // Manuell jeder Zeit per Button möglich.
                ! var updatePlaylistScheduler = "0 0 * * ";
                ! // Sollen Geräte gelistet werden, die nicht Kontrolliert werden können? (TV-Stick, etc.)
                ! // Hier wird dann nur die Gruppe "device" erstellt. "player" und "control" werden nicht erstellt.
                ! var listNonCotrollable = false;
                ! // Liste der bekannten Devicetypen, Geräte mit bekannten DeviceType
                ! // auf das ursprüngliche "anlegen" kann verzichtet werden, da die Capabilities geparst werden.
                ! // Nur Steuerbare Devices werden mit Steuer-Objekten versehen
                ! var knownDeviceType = {
                ! "A3S5BH2HU6VAYF": "Echo Dot 2.Gen",
                ! "AB72C64C86AW2": "Echo",
                ! "A7WXQPH584YP": "Echo 2.Gen",
                ! "A10A33FOX2NUBK": "Echo Spot",
                ! "A1NL4BVLQ4L3N3": "Echo Show",
                ! "A15ERDAKK5HQQG": "Sonos",
                ! "A2E0SNTXJVT7WK": "Fire TV V1",
                ! "ADVBD696BHNV5": "Fire TV Stick V1",
                ! "A2LWARUGJLBYEW": "Fire TV Stick V2",
                ! "A2T0P32DY3F7VB": "echosim.io",
                ! "AILBSA2LNTOYL": "reverb App",
                ! "A2M35JJZWCQOMZ": "Echo Plus"
                ! };
                ! // ----------------------------------------------------------------------------------------------------
                ! // Skript, ab hier nichts ändern
                ! // ----------------------------------------------------------------------------------------------------
                ! // Initiale Variablen setzen
                ! // ------------------------------------------------------
                ! //Script von Stefan.Franke nötig, welches csrf und cookie ausliest
                ! var csrf = getState(idCsrf).val;
                ! var cookie = getState(idCookie).val;
                ! cookie = cookie.replace(/\/g, "");
                ! // Object-Pfad definieren unter dem Devices angelegt werden
                ! var deviceObjectPath = pfad + ".Devices.";
                ! // Node Module https verwenden
                ! var https = require('https');
                ! // CUSTOMERID wird später aus der Geräteliste ausgelesen
                ! var mediaOwnerCustomerId;
                ! // globales Objekt mit allen Devices
                ! var devices = {};
                ! // LoglevelInt defniniern und dann Wert aus den Settings setzen
                ! var logLevelInt = 5;
                ! setLoglevel(logLevel);
                ! // Beim Programmende eine Info ausgeben
                ! onStop(function skriptStop () {
                ! logInfo("
                ** AlexaControl wurde gestoppt ");
                ! }, 2000 /ms/);
                ! // Das eigentliche Programm läuft ab hier
                ! // ------------------------------------------------------
                ! logInfo("
                AlexaControl wurde gestartet ");
                ! if(forceCreation) {
                ! logWarn("Forcecreation ist eingeschaltet. Wenn nicht mehr benötigt, bitte im Skript auf false setzen");
                ! }
                ! // Objekte auslegen und anlegen
                ! initAlexa();
                ! // updates History
                ! schedule(updateHistoryScheduler, function () {rescanHistory();});
                ! // updates Playlists
                ! schedule(updatePlaylistScheduler, function () {updatePlaylists();});
                ! // -------------------------------------------------------------------------------------------------------
                ! // Objekte Auslesen
                ! // -------------------------------------------------------------------------------------------------------
                ! /

                ! * liest per https-GET die aktuellen Playlists von Amazon ein und speichert diese in die "Playlists.X" States
                ! /
                ! function updatePlaylists() {
                ! logInfo('[updatePlaylists]');
                ! // zur Abfrage wird der erste Echo mit MusicPlayer verwendet
                ! var echoWithMusicPlayer = getEchoWithMusicPlayerFromDevices();
                ! var path = '/api/cloudplayer/playlists?deviceSerialNumber=' + echoWithMusicPlayer.serialNumber + '&deviceType=' + echoWithMusicPlayer.deviceType + '&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
                ! httpsReqGet(
                ! path,
                ! function (result) {
                ! tmpListe = JSON.parse(result).playlists;
                ! var playlistsJSON = [];
                ! var playlistsTitles = [];
                ! var playlistsIDs = [];
                ! for (playlist in tmpListe) {
                ! var obj = {
                ! "title": tmpListe[playlist][0].title,
                ! "playlistId": tmpListe[playlist][0].playlistId
                ! };
                ! playlistsJSON.push(obj);
                ! playlistsTitles.push(tmpListe[playlist][0].title);
                ! playlistsIDs.push(tmpListe[playlist][0].playlistId);
                ! }
                ! setState(pfad + ".Playlists.JSON", JSON.stringify(playlistsJSON));
                ! setState(pfad + ".Playlists.Titles", playlistsTitles.join(';'));
                ! setState(pfad + ".Playlists.IDs", playlistsIDs.join(';'));
                ! }
                ! );
                ! }
                ! /

                ! * liest per https-GET die letzten 20 Alexa-History-Einträge von Amazon ein und speichert diese in die "Playlists.X" States
                ! /
                ! function rescanHistory() {
                ! logInfo('[rescanHistory]');
                ! var path = 'https://alexa.amazon.de/api/activities? … 0&offset=1';
                ! httpsReqGet(
                ! path,
                ! function (result) {
                ! activities = JSON.parse(result).activities;
                ! creationTime = getState(pfad + ".History.creationTime").val;
                ! for(var i = (activities.length - 1); i > 0; i--) {
                ! if ((activities__.creationTimestamp > creationTime) || creationTime === null) {
                ! deviceName = getDeviceNameBySerialNumber(activities__.sourceDeviceIds[0].serialNumber);
                ! setState(pfad + ".History.creationTime", activities__.creationTimestamp);
                ! setState(pfad + ".History.deviceName", deviceName);
                ! setState(pfad + ".History.summary", JSON.parse(activities__.description).summary);
                ! }
                ! }
                ! }
                ! );
                ! }
                ! /

                ! * Updated ein Device per DatenpunktName, sowohl "control", als auch "player" wird
                ! * abgerufen und gespeichert befindet sich currentState im Modus "PLAYING", so wird
                ! * mit einem Timeout diese Funktion für das Device erneut aufgerufen
                ! *
                ! * @param string deviceDpName
                ! /
                ! function updateDevice(deviceDpName){
                ! if(typeof(devices[deviceDpName]) != "undefined") {
                ! if (deviceIsControllable(devices[deviceDpName].capabilities)) {
                ! logInfo('[updateDevice] ' + deviceDpName);
                ! var controlPath = deviceObjectPath + clearName(deviceDpName) + ".control";
                ! // deviceObjectPath + clearName(deviceDpName) + ".control.lastState"
                ! getDeviceStateBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, function(deviceState){
                ! // nur updaten, wenn unterschiedlich
                ! if (deviceState.volume != getState(controlPath + ".volume").val) {
                ! setState(controlPath + ".volume", parseInt(deviceState.volume));
                ! }
                ! if(deviceHasMusicPlayer(devices[deviceDpName].capabilities)){
                ! if (deviceState.shuffling != getState(controlPath + ".shuffle").val) {
                ! setState(controlPath + ".shuffle", deviceState.shuffling);
                ! }
                ! if (deviceState.looping != getState(controlPath + ".repeat").val) {
                ! setState(controlPath + ".repeat", deviceState.looping);
                ! }
                ! }
                ! getDevicePlayerBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, function(devicePlayer){
                ! // player
                ! var playerPath = deviceObjectPath + clearName(deviceDpName) + ".player";
                ! setState(playerPath + ".contentType", getStringOrEmpty(deviceState.contentType));
                ! setState(playerPath + ".currentState", getStringOrEmpty(deviceState.currentState));
                ! setState(playerPath + ".imageURL", getStringOrEmpty(deviceState.imageURL));
                ! setState(playerPath + ".muted", deviceState.muted);
                ! setState(playerPath + ".providerId", getStringOrEmpty(deviceState.providerId));
                ! setState(playerPath + ".radioStationId", getStringOrEmpty(deviceState.radioStationId));
                ! setState(playerPath + ".service", getStringOrEmpty(deviceState.service));
                ! var providerName = '';
                ! if ((devicePlayer !== undefined) && ("provider" in devicePlayer) && (devicePlayer.provider !== null)){
                ! providerName = getStringOrEmpty(devicePlayer.provider.providerName);
                ! }
                ! setState(playerPath + ".providerName", providerName);
                ! var title = '';
                ! var interpreter = '';
                ! var album = '';
                ! if ((devicePlayer !== undefined) &&("infoText" in devicePlayer) && (devicePlayer.infoText !== null)){
                ! title = getStringOrEmpty(devicePlayer.infoText.title);
                ! interpreter = getStringOrEmpty(devicePlayer.infoText.subText1);
                ! album = getStringOrEmpty(devicePlayer.infoText.subText2);
                ! }
                ! setState(playerPath + ".title", title);
                ! setState(playerPath + ".interpreter", interpreter);
                ! setState(playerPath + ".album", album);
                ! var mainArtUrl = '';
                ! if ((devicePlayer !== undefined) &&("mainArt" in devicePlayer) && (devicePlayer.mainArt !== null)){
                ! mainArtUrl = getStringOrEmpty(devicePlayer.mainArt.url);
                ! }
                ! setState(playerPath + ".mainArtUrl", mainArtUrl);
                ! var miniArtUrl = '';
                ! if ((devicePlayer !== undefined) &&("miniArt" in devicePlayer) && (devicePlayer.miniArt !== null)){
                ! miniArtUrl = getStringOrEmpty(devicePlayer.miniArt.url);
                ! }
                ! setState(playerPath + ".miniArtUrl", miniArtUrl);
                ! var mediaLength = 0;
                ! var mediaProgress = 0;
                ! var mediaProgressPercent = 0;
                ! if ((devicePlayer !== undefined) &&("progress" in devicePlayer) && (devicePlayer.progress !== null)){
                ! mediaLength = parseInt(devicePlayer.progress.mediaLength);
                ! mediaProgress = parseInt(devicePlayer.progress.mediaProgress);
                ! if (mediaLength > 0) {
                ! mediaProgressPercent = Math.round(((mediaProgress * 100) / mediaLength));
                ! }
                ! }
                ! setState(playerPath + ".mediaLength", mediaLength);
                ! setState(playerPath + ".mediaLengthStr", sekToHMS(mediaLength));
                ! setState(playerPath + ".mediaProgress", mediaProgress);
                ! setState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgress));
                ! setState(playerPath + ".mediaProgressPercent", mediaProgressPercent);
                ! });
                ! });
                ! } else {
                ! logInfo('[updateDevice] Device not controllable: ' + deviceDpName);
                ! }
                ! }else {
                ! logInfo('[updateDevice] Device unknown: ' + deviceDpName);
                ! }
                ! }
                ! /
                *
                ! * Inkrementiert "mediaProgress" alle 2 Sekunden um 2. So wird ein permanentes https-get überflüssig
                ! * ruft sich nach 2 Sekunden erneut selbst auf, wenn "currentState" noch auf "PLAYING" steht.
                ! * ist "mediaProgress" größer als "mediaLength", so ist der Song zu Ende und "updateDevice" wird aufgerufen.
                ! *
                ! * @param string deviceDpName
                ! /
                ! function updateMediaProgress(deviceDpName) {
                ! var playerPath = deviceObjectPath + deviceDpName + ".player";
                ! var currentState = getState(playerPath + ".currentState").val;
                ! var mediaProgress = getState(playerPath + ".mediaProgress").val;
                ! var mediaLength = getState(playerPath + ".mediaLength").val;
                ! if ((currentState == 'PLAYING') ) {
                ! mediaProgressNew = mediaProgress + 2;
                ! // Am Ende des Titels soll neu geladen werden. Ist es Radio (länge = 0) dann alle 200 sekunden
                ! if ((mediaProgressNew > mediaLength) && ((mediaLength > 0) || (mediaProgressNew % 200 < 2))){
                ! setTimeout( function() { updateDevice(deviceDpName); }, 2000 );
                ! }
                ! // Nun mediaProgress und mediaProgressPercent neu berechnen
                ! if (mediaLength > 0) {
                ! mediaProgressPercent = Math.round((((mediaProgressNew) * 100) / mediaLength));
                ! } else {
                ! mediaProgressPercent = 0;
                ! }
                ! setState(playerPath + ".mediaProgressPercent", mediaProgressPercent);
                ! setState(playerPath + ".mediaProgress", mediaProgressNew);
                ! setState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgressNew));
                ! setTimeout( function() { updateMediaProgress(deviceDpName); }, 2000 );
                ! }
                ! }
                ! /
                *
                ! * Ruft den aktuellen State eines Devices per Seriennummer und Type von Amazon ab.
                ! * Gibt die Antwort an "callback(result)" weiter
                ! *
                ! * @param string serialNumber
                ! * @param string deviceType
                ! * @param function callback
                ! /
                ! function getDeviceStateBySerialAndType(serialNumber, deviceType, callback) {
                ! httpsReqGet(
                ! '/api/media/state?deviceSerialNumber=' + serialNumber + '&deviceType=' + deviceType,
                ! function(result) {
                ! // Es kommt vor, dass Geräte nicht antworten, weil sie nicht aktiv sind. Dann greift hier der Dummy-Wert
                ! if (result == '{"message":null}') {
                ! result = JSON.stringify({
                ! "clientId":null,
                ! "contentId":null,
                ! "contentType":null,
                ! "currentState":"IDLE",
                ! "imageURL":null,
                ! "isDisliked":false,
                ! "isLiked":false,
                ! "looping":false,
                ! "mediaOwnerCustomerId":null,
                ! "muted":false,
                ! "programId":null,
                ! "progressSeconds":0,
                ! "providerId":null,
                ! "queue":null,
                ! "queueId":null,
                ! "queueSize":0,
                ! "radioStationId":null,
                ! "radioVariety":0,
                ! "referenceId":null,
                ! "service":null,
                ! "shuffling":false,
                ! "timeLastShuffled":0,
                ! "volume":0
                ! });
                ! }
                ! if(callback !== undefined && typeof callback === 'function') callback(JSON.parse(result));
                ! }
                ! );
                ! }
                ! /
                *
                ! * Ruft den aktuellen State eines Devices per DatenpunktNamen von Amazon ab.
                ! * Gibt die Antwort an "callback(result)" weiter
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function getDeviceState(deviceDpName, callback) {
                ! getDeviceStateBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, callback);
                ! }
                ! /
                *
                ! * Ruft die aktuelle PlayerInfo eines Devices per Seriennummer und Type von Amazon ab.
                ! * Gibt die Antwort an "callback(result)" weiter
                ! *
                ! * @param string serialNumber
                ! * @param string deviceType
                ! * @param function callback
                ! /
                ! function getDevicePlayerBySerialAndType(serialNumber, deviceType, callback) {
                ! httpsReqGet(
                ! '/api/np/player?deviceSerialNumber=' + serialNumber + '&deviceType=' + deviceType,
                ! function(result) {
                ! // Es kommt vor, dass Geräte nicht antworten, weil sie nicht aktiv sind. Dann greift hier der Dummy-Wert
                ! if (result == '{"message":null}') {
                ! result = JSON.stringify({
                ! "playerInfo":{
                ! "hint":null,
                ! "infoText":null,
                ! "isPlayingInLemur":false,
                ! "lemurVolume":null,
                ! "lyrics":null,
                ! "mainArt":null,
                ! "mediaId":null,
                ! "miniArt":null,
                ! "miniInfoText":null,
                ! "playbackSource":null,
                ! "playingInLemurId":null,
                ! "progress":null,
                ! "provider":null,
                ! "queueId":null,
                ! "state":null,
                ! "template":null,
                ! "transport":null,
                ! "volume":null
                ! }
                ! });
                ! }
                ! if(callback !== undefined && typeof callback === 'function') callback(JSON.parse(result).playerInfo);
                ! }
                ! );
                ! }
                ! /
                *
                ! * Ruft die aktuelle PlayerInfo eines Devices per DatenpunktNamen von Amazon ab.
                ! * Gibt die Antwort an "callback(result)" weiter
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function getDevicePlayer(deviceDpName, callback) {
                ! getDevicePlayerBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, callback);
                ! }
                ! /
                *
                ! * liest per https-GET alle Alexa-fähigen Geräte neu ein und updated bei allen
                ! * bereits bekannten Geräten die Infos, wie z.B. Onlinestatus, WLAN, etc.
                ! /
                ! function updateAlexa(){
                ! logInfo('[updateAlexa]');
                ! httpsReqGet('/api/devices/device', function(result) {
                ! // Falls Result leer ist, soll nichts weiter gemacht werden
                ! if(!result) return logWarn("Es konnten keine Daten ermittelt werden! Cookie richtig?");
                ! logDebug(result);
                ! var alexaDeviceObj = JSON.parse(result);
                ! var numberOfDevices = alexaDeviceObj.devices.length;
                ! logInfo("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices);
                ! if (numberOfDevices < 1) {
                ! return logWarn("Error: Skript konnte keine Geräte abfragen");
                ! }
                ! // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben
                ! mediaOwnerCustomerId = getStringOrEmpty(alexaDeviceObj.devices[0].deviceOwnerCustomerId);
                ! // Devices
                ! for(var i = 0; i < numberOfDevices; i++) {
                ! // Nur bekannte Geraete updaten
                ! if(typeof(devices[clearName(alexaDeviceObj.devices_[i].accountName)]) != "undefined") {
                ! // Pruefen, ob das Geraet noch das selbe ist
                ! if (devices[clearName(alexaDeviceObj.devices_[i].accountName)].serialNumber != alexaDeviceObj.devices__.serialNumber){
                ! logError('Das Geraet "' + clearName(alexaDeviceObj.devices__.accountName) + '" hat nach update eine andere Seriennummer!');
                ! } else {
                ! var devicePath = deviceObjectPath + clearName(alexaDeviceObj.devices__.accountName) + ".device";
                ! httpsReqGet(
                ! '/api/device-wifi-details?deviceSerialNumber=' + alexaDeviceObj.devices__.serialNumber + '&deviceType=' + alexaDeviceObj.devices_.deviceType,
                ! function(result) {
                ! setState(devicePath + ".essid", getStringOrEmpty(JSON.parse(result).essid));
                ! setState(devicePath + ".macAddress", getStringOrEmpty(JSON.parse(result).macAddress));
                ! }
                ! );
                ! setState(devicePath + ".language", getStringOrEmpty(alexaDeviceObj.devices_.language));
                ! setState(devicePath + ".online", alexaDeviceObj.devices_.online);
                ! setState(devicePath + ".parentClusters", getStringOrEmpty(alexaDeviceObj.devices_.parentClusters));
                ! setState(devicePath + ".softwareVersion", getStringOrEmpty(alexaDeviceObj.devices_.softwareVersion));
                ! // Device updaten
                ! updateDevice(clearName(alexaDeviceObj.devices_.accountName));
                ! }
                ! }
                ! }
                ! });
                ! }
                ! // –-----------------------------------------------------------------------------------------------------
                ! // Objekte Anlegen
                ! // -------------------------------------------------------------------------------------------------------
                ! /
                *
                ! * liest per https-GET alle Alexa-fähigen Geräte ein und legt die Objekte an
                ! /
                ! function initAlexa() {
                ! httpsReqGet('/api/devices/device', function(result) {
                ! // Falls Result leer ist, soll nichts weiter gemacht werden
                ! if(!result) return logWarn("Es konnten keine Daten ermittelt werden! Cookie richtig?");
                ! logDebug(result);
                ! var alexaDeviceObj = JSON.parse(result);
                ! var numberOfDevices = alexaDeviceObj.devices.length;
                ! logInfo("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices);
                ! if (numberOfDevices < 1) {
                ! return logWarn("Error: Skript konnte keine Geräte abfragen");
                ! }
                ! // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben
                ! mediaOwnerCustomerId = alexaDeviceObj.devices[0].deviceOwnerCustomerId;
                ! createDeviceState(pfad + ".mediaOwnerCustomerId", mediaOwnerCustomerId, forceCreation, {name:"Individuelle Kunden ID", type:"string", role:"value"});
                ! // Devices
                ! for(var i = 0; i < numberOfDevices; i++) {
                ! if (listNonCotrollable || deviceIsControllable(alexaDeviceObj.devices_.capabilities)) {
                ! devices[clearName(alexaDeviceObj.devices[i].accountName)] = createDevice(alexaDeviceObj.devices_, forceCreation);
                ! }
                ! }
                ! // Update
                ! createState(
                ! pfad + ".update",
                ! false,
                ! forceCreation,
                ! {name:"Update Devices", type:"boolean", role:"button"},
                ! null,
                ! function () {
                ! setTimeout(
                ! function() {
                ! logInfo("CreateON: " + pfad + ".update");
                ! on({id: "javascript." + instance + "." + pfad + ".update", change: "any"},
                ! function (obj){
                ! unsetButtonFirst(obj, function (obj) {updateAlexa();});
                ! })
                ! }
                ! ,
                ! 3000
                ! );
                ! }
                ! );
                ! // Playlists
                ! createDeviceState(pfad + ".Playlists.JSON", null, forceCreation, {name:"Playlists als JSON", type:"string", role:"state"});
                ! createDeviceState(pfad + ".Playlists.Titles", null, forceCreation, {name:"Playlist Titel als Liste fuer Dropdown", type:"string", role:"state"});
                ! createDeviceState(pfad + ".Playlists.IDs", null, forceCreation, {name:"Playlist IDs als Liste fuer Dropdown", type:"string", role:"state"});
                ! createState(
                ! pfad + ".Playlists.update",
                ! false,
                ! forceCreation,
                ! {name:"Update Playlists", type:"boolean", role:"button"},
                ! null,
                ! function () {
                ! setTimeout(
                ! function() {
                ! logInfo("CreateON: " + pfad + ".Playlists.update");
                ! on({id: "javascript." + instance + "." + pfad + ".Playlists.update", change: "any"},
                ! function (obj){
                ! unsetButtonFirst(obj, function (obj) {updatePlaylists();});
                ! })
                ! }
                ! ,
                ! 3000
                ! );
                ! }
                ! );
                ! // Einmalig die Playlists abfragen
                ! updatePlaylists();
                ! // History
                ! createState(pfad + ".History.creationTime", null, forceCreation, {name:"Timestamp", type:"number", role:"state"});
                ! createState(pfad + ".History.deviceName", null, forceCreation, {name:"deviceName", type:"string", role:"state"});
                ! createState(pfad + ".History.summary", null, forceCreation, {name:"summary", type:"string", role:"state"});
                ! createState(
                ! pfad + ".History.update",
                ! false,
                ! forceCreation,
                ! {name:"Update History", type:"boolean", role:"button"},
                ! null,
                ! function () {
                ! setTimeout(
                ! function() {
                ! logInfo("CreateON: " + pfad + ".History.update");
                ! on({id: "javascript." + instance + "." + pfad + ".History.update", change: "any"},
                ! function (obj){
                ! unsetButtonFirst(obj, function (obj) {rescanHistory();});
                ! })
                ! }
                ! ,
                ! 3000
                ! );
                ! }
                ! );
                ! // Erstmalig die History abgragen
                ! rescanHistory();
                ! });
                ! }
                ! /
                *
                ! * Erzeugt alle States zu einem übergebenen Device-Objekt. Anhand der "capabilities"
                ! * des Devices, werden, ggf. "control" und "player" States erstellt.
                ! *
                ! * @param object amazonDeviceObject
                ! * @param boolean forceCreation
                ! /
                ! function createDevice(amazonDeviceObject, forceCreation) {
                ! logInfo('createDevice: '+ amazonDeviceObject.accountName);
                ! var devicePath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".device";
                ! // device
                ! createDeviceState(devicePath + ".accountName", getStringOrEmpty(amazonDeviceObject.accountName), forceCreation, {name:"Name", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".capabilities", getStringOrEmpty(JSON.stringify(amazonDeviceObject.capabilities)), forceCreation, {name:"Fähigkeiten", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".clusterMembers", getStringOrEmpty(JSON.stringify(amazonDeviceObject.clusterMembers)), forceCreation, {name:"GruppenMitglieder", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceAccountId", getStringOrEmpty(amazonDeviceObject.deviceAccountId), forceCreation, {name:"AccountId", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceFamily", getStringOrEmpty(amazonDeviceObject.deviceFamily), forceCreation, {name:"DeviceFamily", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceOwnerCustomerId", getStringOrEmpty(amazonDeviceObject.deviceOwnerCustomerId), forceCreation, {name:"deviceOwnerCustomerId", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceType", getStringOrEmpty(amazonDeviceObject.deviceType), forceCreation, {name:"deviceType", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceTypeString", getStringOrEmpty(deviceTypeStr(amazonDeviceObject.deviceType)), forceCreation, {name:"deviceType als String", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".deviceTypeFriendlyName", getStringOrEmpty(amazonDeviceObject.deviceTypeFriendlyName), forceCreation, {name:"deviceTypeFriendlyName", type:"string", role:"value"});
                ! httpsReqGet(
                ! '/api/device-wifi-details?deviceSerialNumber=' + amazonDeviceObject.serialNumber + '&deviceType=' + amazonDeviceObject.deviceType,
                ! function(result) {
                ! createDeviceState(devicePath + ".essid", getStringOrEmpty(JSON.parse(result).essid), forceCreation, {name:"essid", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".macAddress", getStringOrEmpty(JSON.parse(result).macAddress), forceCreation, {name:"macAddress", type:"string", role:"value"});
                ! }
                ! );
                ! createDeviceState(devicePath + ".language", getStringOrEmpty(amazonDeviceObject.language), forceCreation, {name:"language", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".online", amazonDeviceObject.online, forceCreation, {name:"online (Klappt nur bei ECHOs)", type:"boolean", role:"value"});
                ! createDeviceState(devicePath + ".parentClusters", getStringOrEmpty(amazonDeviceObject.parentClusters), forceCreation, {name:"Mitglied in dieser Gruppe", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".serialNumber", getStringOrEmpty(amazonDeviceObject.serialNumber), forceCreation, {name:"serialNumber", type:"string", role:"value"});
                ! createDeviceState(devicePath + ".softwareVersion", getStringOrEmpty(amazonDeviceObject.softwareVersion), forceCreation, {name:"softwareVersion", type:"string", role:"value"});
                ! if (deviceIsControllable(amazonDeviceObject.capabilities)) {
                ! createDeviceControl(amazonDeviceObject, forceCreation);
                ! }
                ! return {
                ! 'serialNumber' : amazonDeviceObject.serialNumber,
                ! 'deviceType' : amazonDeviceObject.deviceType,
                ! 'capabilities' : amazonDeviceObject.capabilities
                ! };
                ! }
                ! /
                *
                ! * Erzeugt alle "control" und "player" States zu einem übergebenen Device-Objekt.
                ! * Für Initial-Werte wird das Device bei Amazon zunächst abgefragt
                ! *
                ! * @param object amazonDeviceObject
                ! * @param boolean forceCreation
                ! /
                ! function createDeviceControl(amazonDeviceObject, forceCreation) {
                ! logInfo('createDeviceControl: '+ amazonDeviceObject.accountName);
                ! var controlPath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".control";
                ! // control
                ! createDeviceState(controlPath + ".LastStatus", 'INIT', forceCreation, {name:"Letzter Status", type:"string", role:"value"});
                ! createDeviceControlState(controlPath + ".updateDevice", false, forceCreation, {name:"Device abfragen", type:"boolean", role:"button"});
                ! // deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".control.lastState"
                ! getDeviceStateBySerialAndType(amazonDeviceObject.serialNumber, amazonDeviceObject.deviceType, function(deviceState){
                ! createDeviceControlState(controlPath + ".volume", parseInt(deviceState.volume), forceCreation, {name:"Volume in Prozent(0-100)", type:"number", role:"level.volume"});
                ! createDeviceControlState(controlPath + ".pause", false, forceCreation, {name:"Pause", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".play", false, forceCreation, {name:"Play", type:"boolean", role:"button"});
                ! if(deviceHasMusicPlayer(amazonDeviceObject.capabilities)){
                ! createDeviceControlState(controlPath + ".next", false, forceCreation, {name:"Next (nächster Titel)", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".previous", false, forceCreation, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".forward", false, forceCreation, {name:"Forward (Hörbuch 30 Sekunden vor)", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".rewind", false, forceCreation, {name:"Rewind (Hörbuch 30 Sekunden zurück)", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".previous", false, forceCreation, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
                ! createDeviceControlState(controlPath + ".shuffle", deviceState.shuffling, forceCreation, {name:"Shuffel an/aus", type:"boolean", role:"switch"});
                ! createDeviceControlState(controlPath + ".repeat", deviceState.looping, forceCreation, {name:"Repeat an/aus)", type:"boolean", role:"switch"});
                ! createDeviceControlState(controlPath + ".playlistId", false, forceCreation, {name:"spiele Playlist", type:"string", role:"control.value"});
                ! }
                ! if(deviceHasTuneIn(amazonDeviceObject.capabilities)){
                ! createDeviceControlState(controlPath + ".radio", false, forceCreation, {name:"Letzte Radiostation an/aus", type:"boolean", role:"switch"});
                ! createDeviceControlState(controlPath + ".tunein", defaultRadiostation, forceCreation, {name:"tunein Radiosenderkennung", type:"string", role:"control.value"});
                ! }
                ! getDevicePlayerBySerialAndType(amazonDeviceObject.serialNumber, amazonDeviceObject.deviceType, function(devicePlayer){
                ! // player
                ! var playerPath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".player";
                ! createDeviceState(playerPath + ".contentType", getStringOrEmpty(deviceState.contentType), forceCreation, {name:"contentType", type:"string", role:"value"}); // "LIVE_STATION" | "TRACKS" | "CUSTOM_STATION"
                ! createDeviceControlState(playerPath + ".currentState", getStringOrEmpty(deviceState.currentState), forceCreation, {name:"currentState", type:"string", role:"value"}); // "PAUSED" | "PLAYING"
                ! createDeviceState(playerPath + ".imageURL", getStringOrEmpty(deviceState.imageURL), forceCreation, {name:"Grosses Bild", type:"string", role:"value"});
                ! createDeviceState(playerPath + ".muted", deviceState.muted, forceCreation, {name:"muted", type:"boolean", role:"value"});
                ! createDeviceState(playerPath + ".providerId", getStringOrEmpty(deviceState.providerId), forceCreation, {name:"providerId", type:"string", role:"value"}); // "TUNE_IN" | "CLOUD_PLAYER" | "ROBIN"
                ! createDeviceState(playerPath + ".radioStationId", getStringOrEmpty(deviceState.radioStationId), forceCreation, {name:"radioStationId", type:"string", role:"value"}); // "s24885" | null
                ! createDeviceState(playerPath + ".service", getStringOrEmpty(deviceState.service), forceCreation, {name:"service", type:"string", role:"value"}); // "TUNE_IN" | "CLOUD_PLAYER" | "PRIME_STATION"
                ! var providerName = null;
                ! if ((devicePlayer !== undefined) &&("provider" in devicePlayer) && (devicePlayer.provider !== null)){
                ! providerName = getStringOrEmpty(devicePlayer.provider.providerName);
                ! }
                ! createDeviceState(playerPath + ".providerName", providerName, forceCreation, {name:"active providerName", type:"string", role:"value"}); // "Amazon Music" | "TuneIn Live-Radio"
                ! var title = '';
                ! var interpreter = '';
                ! var album = '';
                ! if ((devicePlayer !== undefined) &&("infoText" in devicePlayer) && (devicePlayer.infoText !== null)){
                ! title = getStringOrEmpty(devicePlayer.infoText.title);
                ! interpreter = getStringOrEmpty(devicePlayer.infoText.subText1);
                ! album = getStringOrEmpty(devicePlayer.infoText.subText2);
                ! }
                ! createDeviceState(playerPath + ".title", title, forceCreation, {name:"active title", type:"string", role:"value"});
                ! createDeviceState(playerPath + ".interpreter", interpreter, forceCreation, {name:"active interpreter", type:"string", role:"value"});
                ! createDeviceState(playerPath + ".album", album, forceCreation, {name:"active album", type:"string", role:"value"});
                ! var mainArtUrl = '';
                ! if ((devicePlayer !== undefined) &&("mainArt" in devicePlayer) && (devicePlayer.mainArt !== null)){
                ! mainArtUrl = getStringOrEmpty(devicePlayer.mainArt.url);
                ! }
                ! createDeviceState(playerPath + ".mainArtUrl", mainArtUrl, forceCreation, {name:"active mainArtUrl", type:"string", role:"value"});
                ! var miniArtUrl = '';
                ! if ((devicePlayer !== undefined) &&("miniArt" in devicePlayer) && (devicePlayer.miniArt !== null)){
                ! miniArtUrl = getStringOrEmpty(devicePlayer.miniArt.url);
                ! }
                ! createDeviceState(playerPath + ".miniArtUrl", miniArtUrl, forceCreation, {name:"active miniArtUrl", type:"string", role:"value"});
                ! var mediaLength = 0;
                ! var mediaProgress = 0;
                ! var mediaProgressPercent = 0;
                ! if ((devicePlayer !== undefined) &&("progress" in devicePlayer) && (devicePlayer.progress !== null)) {
                ! mediaLength = parseInt(devicePlayer.progress.mediaLength);
                ! mediaProgress = parseInt(devicePlayer.progress.mediaProgress);
                ! if (mediaLength > 0) {
                ! mediaProgressPercent = Math.round(((mediaProgress * 100) / mediaLength));
                ! }
                ! }
                ! createDeviceState(playerPath + ".mediaLength", mediaLength, forceCreation, {name:"active mediaLength", type:"number", role:"value"});
                ! createDeviceState(playerPath + ".mediaLengthStr", sekToHMS(mediaLength), forceCreation, {name:"active mediaLength als (HH:)MM:SS", type:"string", role:"value"});
                ! createDeviceState(playerPath + ".mediaProgress", mediaProgress, forceCreation, {name:"active mediaProgress", type:"number", role:"value"});
                ! createDeviceState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgress), forceCreation, {name:"active mediaProgress als (HH:)MM:SS", type:"string", role:"value"});
                ! createDeviceState(playerPath + ".mediaProgressPercent", mediaProgressPercent, forceCreation, {name:"active mediaProgressPercent", type:"number", role:"value"});
                ! });
                ! });
                ! }
                ! /
                *
                ! * Erzeugt einen State und macht danach einen Logeintrag
                ! *
                ! * @param string objectdevicePath
                ! * @param mixed initialValue
                ! * @param boolean forceCreation
                ! * @param object common
                ! /
                ! function createDeviceState(objectdevicePath, initialValue, forceCreation, common) {
                ! createState(objectdevicePath, initialValue, forceCreation, common, null, function(){logInfo('createState: ' + objectdevicePath)});
                ! }
                ! /
                *
                ! * Erzeugt einen State und macht danach einen Logeintrag
                ! * Dann wird für den State eine "on()-Funktion" erzeugt, die die gewünschte Funktion ausfürht
                ! *
                ! * @param string objectdevicePath
                ! * @param mixed initialValue
                ! * @param boolean forceCreation
                ! * @param object common
                ! /
                ! function createDeviceControlState(objectdevicePath, initialValue, forceCreation, common) {
                ! createState(
                ! objectdevicePath,
                ! initialValue,
                ! forceCreation,
                ! common,
                ! null,
                ! function () {
                ! logInfo('createState: ' + objectdevicePath);
                ! setTimeout(
                ! function() {
                ! logInfo("CreateON: " + objectdevicePath);
                ! on({id: "javascript." + instance + "." + objectdevicePath, change: "any"},
                ! function (obj){
                ! var objArr = obj.id.match(/(^.+).(.+).(.+).(.+)$/, ""); //Aufteilung in devicePath + deviceDpName + CMD
                ! var deviceDpName = objArr[2];
                ! var cmd = objArr[4];
                ! logDebug("Device: " + deviceDpName+", Kommando: " + cmd);
                ! parameter = obj.state.val;
                ! var reloadCallback = function() {setTimeout(function() {updateDevice(deviceDpName);}, 3000);};
                ! switch (cmd) {
                ! // Buttons, werden immer wieder auf false gesetzt
                ! case "updateDevice":
                ! unsetButtonFirst(obj, function (obj) {updateDevice(deviceDpName);});
                ! break;
                ! case "pause":
                ! unsetButtonFirst(obj, function (obj) {setPause(deviceDpName, reloadCallback);});
                ! break;
                ! case "play":
                ! unsetButtonFirst(obj, function (obj) {setPlay(deviceDpName, reloadCallback);});
                ! break;
                ! case "next":
                ! unsetButtonFirst(obj, function (obj) {setNext(deviceDpName, reloadCallback);});
                ! break;
                ! case "previous":
                ! unsetButtonFirst(obj, function (obj) {setPrevious(deviceDpName, reloadCallback);});
                ! break;
                ! case "forward":
                ! unsetButtonFirst(obj, function (obj) {setForward(deviceDpName, reloadCallback);});
                ! break;
                ! case "rewind":
                ! unsetButtonFirst(obj, function (obj) {setRewind(deviceDpName, reloadCallback);});
                ! break;
                ! //Switch
                ! case "shuffle":
                ! if(parameter === null){
                ! logWarn("Alexa Shuffle: kein true/false angegeben. Auf true gesetzt.");
                ! parameter = true;
                ! }
                ! setShuffle(deviceDpName, parameter);
                ! break;
                ! case "repeat":
                ! if(parameter === null){
                ! logWarn("Alexa Repeat: kein true/false angegeben. Auf true gesetzt.");
                ! parameter = true;
                ! }
                ! setRepeat(deviceDpName, parameter);
                ! break;
                ! case "radio":
                ! if(obj.state.val) {
                ! // Letzte Radiostation einschlaten
                ! var stationId = getState(deviceObjectPath + deviceDpName + ".control.tunein").val;
                ! setTuneIn(deviceDpName,stationId, reloadCallback);
                ! } else {
                ! // Musik auf Pause.
                ! setPause(deviceDpName, reloadCallback);
                ! }
                ! break;
                ! case "volume":
                ! if(!parameter ||parameter === null){
                ! logWarn("Alexa Volume: keine Lautstärke angegeben. Parameter fehlt.");
                ! break;
                ! }
                ! parameter = parseInt(parameter);
                ! if(parameter < 0) {
                ! parameter = 0;
                ! logWarn("Alexa Volume: ungültige Lautsträke angegeben (<0). Auf 0 gesetzt.");
                ! }
                ! if(parameter > 100) {
                ! parameter = 100;
                ! logWarn("Alexa Volume: ungültige Lautsträke angegeben (>100). Auf 100 gesetzt.");
                ! }
                ! setVolume(deviceDpName, parameter);
                ! break;
                ! case "playlistId":
                ! setPlaylistId(deviceDpName, parameter, reloadCallback);
                ! break;
                ! case "tunein":
                ! setTuneIn(deviceDpName,parameter, reloadCallback);
                ! break;
                ! case "currentState":
                ! // den aktuellen "mediaProgress" berechnen, statt ihn immer neu runterzuladen
                ! if ((obj.oldState.val == 'PAUSED') && (obj.state.val == 'PLAYING')) {
                ! // Wechsel von Pause zu Playing
                ! updateMediaProgress(deviceDpName);
                ! } else if (obj.state.val == 'PLAYING') {
                ! // war vorher nicht Pause, nun aber Playing, dann überprüfen, ob sich "mediaProgress"
                ! // innerhalb einer gewissen Zeit verändert (dann wurde die Funktion bereits ausgeführt)
                ! var playerPath = deviceObjectPath + deviceDpName + ".player";
                ! setTimeout( function() {
                ! var mediaProgress = getState(playerPath + ".mediaProgress").val;
                ! setTimeout( function() {
                ! var mediaProgressNew = getState(playerPath + ".mediaProgress").val;
                ! // Wurde mediaProgress in der Zeit trotz PLAYING nicht verändert, dann trotzdem ausführen
                ! if (mediaProgressNew == mediaProgress){
                ! setState(playerPath + ".mediaProgress", mediaProgressNew + 7);
                ! updateMediaProgress(deviceDpName);
                ! }
                ! }, 5000 );
                ! }, 3000 );
                ! }
                ! break;
                ! default:
                ! logWarn("Kommando << "+cmd+" >> im Skript nicht behandelt");
                ! break;
                ! }
                ! })
                ! }
                ! ,
                ! 3000
                ! );
                ! }
                ! );
                ! }
                ! // –-----------------------------------------------------------------------------------------------------
                ! // HTTPS-GET/POST-Funktionen
                ! // -------------------------------------------------------------------------------------------------------
                ! /
                *
                ! * Setzt die Options für den https Request
                ! *
                ! * @param string path
                ! * @param string method - Should be GET oder POST
                ! /
                ! function setOptions(path,method) {
                ! var options = {
                ! "host": 'layla.amazon.de',
                ! "path": path,
                ! "method": method,
                ! "timeout":10000,
                ! "headers": {
                ! 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
                ! 'Content-Type': 'text/plain',
                ! 'csrf' : csrf,
                ! 'Cookie' : cookie
                ! }
                ! };
                ! return options;
                ! }
                ! /
                *
                ! * Erzeugt eine GET Anfrage
                ! * @param string path
                ! * @param function callback
                ! /
                ! function httpsReqGet(path,callback) {
                ! logDebug("Abfrage " + path + " an Alexa gesendet");
                ! var options = setOptions(path,"GET");
                ! var req = https.get(options, function getDevices(res) {
                ! logDebug('STATUS: ' + res.statusCode) + ": " + statusCode(res.statusCode); // Statuscode
                ! logDebug('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
                ! // Buffer the body entirely for processing as a whole.
                ! var bodyChunks = [];
                ! var chunkLine = 0;
                ! res.on('data', function(chunk) {
                ! chunkLine = chunkLine + 1;
                ! // Hier können die einzelnen Zeilen verarbeitet werden...
                ! logDebug("Zeilennummer: " + chunkLine+ " ,Inhalt: " + chunk);
                ! bodyChunks.push(chunk);
                ! }).on('end', function() {
                ! logDebug("ARRAY mit den einzelnen Zeilen: " + bodyChunks);
                ! logDebug("ARRAY Länge: " + bodyChunks.length);
                ! var body = Buffer.concat(bodyChunks);
                ! // ...und/oder das Gesamtergebnis (body).
                ! if(!body) log("keine Daten erhalten","warn");
                ! logDebug('BODY: ' + body);
                ! if(callback !== undefined && typeof callback === 'function') return callback(body);
                ! });
                ! });
                ! req.on('error', function(e) { // Fehler abfangen
                ! log('ERROR: ' + e.message,"warn");
                ! log("keinen gültigen Callback gefunden","warn");
                ! ok = false;
                ! });
                ! req.end();
                ! }
                ! /
                *
                ! * Setzt das Device auf die Lautstärke
                ! *
                ! * @param string deviceDpName
                ! * @param integer volumeLevel
                ! * @param function callback
                ! /
                ! function setVolume(deviceDpName, volumeLevel, callback) {httpsPostCmd(deviceDpName, '{"type":"VolumeLevelCommand","volumeLevel":' + volumeLevel + '}' , callback);}
                ! /
                *
                ! * Setzt das Device auf PLAY
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setPlay(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PlayCommand"}', callback);}
                ! /
                *
                ! * Setzt das Device auf PAUSE
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setPause(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PauseCommand"}', callback);}
                ! /
                *
                ! * Setzt das Device auf NEXT
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setNext(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"NextCommand"}', callback);}
                ! /
                *
                ! * Setzt das Device auf PREVIOUS
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setPrevious(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PreviousCommand"}', callback);}
                ! /
                *
                ! * Setzt das Device auf FORWARD
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setForward(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"ForwardCommand"}', callback);}
                ! /
                *
                ! * Setzt das Device auf REWIND
                ! *
                ! * @param string deviceDpName
                ! * @param function callback
                ! /
                ! function setRewind(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"RewindCommand"}', callback);}
                ! /
                *
                ! * Setzt für das Device SHUFFLE auf den gewünschten zustand
                ! *
                ! * @param string deviceDpName
                ! * @param boolean state
                ! * @param function callback
                ! /
                ! function setShuffle(deviceDpName, state, callback) {httpsPostCmd(deviceDpName, '{"type":"ShuffleCommand","shuffle":' + state + '}', callback);}
                ! /
                *
                ! * Setzt für das Device REPEAT auf den gewünschten zustand
                ! *
                ! * @param string deviceDpName
                ! * @param boolean state
                ! * @param function callback
                ! /
                ! function setRepeat(deviceDpName, state, callback) {httpsPostCmd(deviceDpName, '{"type":"RepeatCommand","repeat":' + state + '}', callback);}
                ! /
                *
                ! * Schickt ein Kommando an Alexa
                ! *
                ! * @param string deviceDpName
                ! * @param string postData
                ! * @param function callback
                ! /
                ! function httpsPostCmd(deviceDpName, postData, callback) {
                ! logInfo("[httpsPostCmd] Device: " + deviceDpName + " - Kommando: " + postData);
                ! var path = '/api/np/command?'
                ! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
                ! + '&deviceType=' + devices[deviceDpName].deviceType ;
                ! httpsPost(deviceDpName, path, postData, callback);
                ! }
                ! /
                *
                ! * Startet auf dem Device den Radiosender
                ! *
                ! * @param string deviceDpName
                ! * @param string stationId
                ! * @param function callback
                ! /
                ! function setTuneIn(deviceDpName,stationId, callback) {
                ! logInfo("[setTuneIn] Device: " + deviceDpName + " - TuneIn-StationId: " + stationId);
                ! var path = '/api/tunein/queue-and-play?'
                ! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
                ! + '&deviceType=' + devices[deviceDpName].deviceType
                ! + '&guideId=' + stationId
                ! + '&contentType=station&callSign=&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
                ! httpsPost(deviceDpName, path, '', callback);
                ! }
                ! /
                *
                ! * Startet auf dem Device die Playlist
                ! *
                ! * @param string deviceDpName
                ! * @param string playlistId
                ! * @param function callback
                ! /
                ! function setPlaylistId(deviceDpName, playlistId, callback) {
                ! logInfo("[setPlaylistId] Device: " + deviceDpName + " - PlaylistId: " + playlistId);
                ! var path = '/api/cloudplayer/queue-and-play?'
                ! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
                ! + '&deviceType=' + devices[deviceDpName].deviceType
                ! + '&shuffle=false'
                ! + '&contentType=station&callSign=&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
                ! httpsPost(deviceDpName, path, '{"playlistId":"' + playlistId + '"}', callback);
                ! }
                ! /
                *
                ! * Erzeugt eine POST Anfrage und setzt den Status-Code
                ! * der Anfrage in das 'control.LastStatus' Feld
                ! *
                ! * @param string deviceDpName
                ! * @param string path
                ! * @param string postData
                ! * @param function callback
                ! /
                ! function httpsPost(deviceDpName, path, postData, callback) {
                ! logDebug("[httpsPost] Device: " + deviceDpName + " Path: " + path + " postData: " + postData);
                ! var options = setOptions(path,"POST");
                ! // request object
                ! var req = https.request(options, function (res) {
                ! var result = '';
                ! res.on('data', function (chunk) {
                ! result += chunk;
                ! });
                ! res.on('end', function () {
                ! logDebug(result);
                ! setState(deviceObjectPath + deviceDpName +".control.LastStatus",res.statusCode.toString()+" " + statusCode(res.statusCode));
                ! if(res.statusCode != 200) {
                ! logWarn("Negative Rückmeldung von Alexa: " + res.statusCode + ": " + statusCode(res.statusCode));
                ! logWarn("Gesendetes Kommando: " + postData);
                ! } else {
                ! logDebug('STATUS: ' + res.statusCode + ": " + statusCode(res.statusCode)); // Statuscode
                ! }
                ! if(res.statusCode != 200){
                ! logWarn('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
                ! }
                ! if(callback !== undefined && typeof callback === 'function') callback(result);
                ! });
                ! res.on('error', function (err) {
                ! logWarn('ERROR: ' + err.message);
                ! })
                ! });
                ! // req error
                ! req.on('error', function (err) {
                ! logWarn('ERROR: ' + err.message);
                ! });
                ! //send request witht the postData form
                ! req.write(postData);
                ! req.end();
                ! }
                ! // –-----------------------------------------------------------------------------------------------------
                ! // Hilfs-Funktionen
                ! // -------------------------------------------------------------------------------------------------------
                ! /
                *
                ! * Setzt das gewünschte Loglevel
                ! *
                ! * @param string level
                ! /
                ! function setLoglevel(level) {
                ! switch(level.toLowerCase()) {
                ! case 'debug':
                ! logLevelInt = 0;
                ! break;
                ! case 'info':
                ! logLevelInt = 1;
                ! break;
                ! case 'warn':
                ! logLevelInt = 2;
                ! break;
                ! case 'error':
                ! logLevelInt = 3;
                ! break;
                ! case 'none':
                ! logLevelInt = 4;
                ! break;
                ! default:
                ! logLevelInt = 2;
                ! break;
                ! }
                ! }
                ! /
                *
                ! * Logt eine DEBUG Message
                ! * (wird als info geloggt, da Debug nicht angezeigt wird)
                ! *
                ! * @param string msg
                ! /
                ! function logDebug(msg) {
                ! if (logLevelInt <= 0) {
                ! log(msg, "info");
                ! }
                ! }
                ! /
                *
                ! * Logt eine INFO Message
                ! *
                ! * @param string msg
                ! /
                ! function logInfo(msg) {
                ! if (logLevelInt <= 1) {
                ! log(msg, "info");
                ! }
                ! }
                ! /
                *
                ! * Logt eine WARN Message
                ! *
                ! * @param string msg
                ! /
                ! function logWarn(msg) {
                ! if (logLevelInt <= 2) {
                ! log(msg, "warn");
                ! }
                ! }
                ! /
                *
                ! * Logt eine ERROR Message
                ! *
                ! * @param string msg
                ! /
                ! function logError(msg) {
                ! if (logLevelInt <= 3) {
                ! log(msg, "error");
                ! }
                ! }
                ! /
                *
                ! * Durchsucht ein Array nach needle und
                ! * liefert bei Erfolg TRUE
                ! *
                ! * @param string needle
                ! * @param array haystack
                ! * @return boolean
                ! /
                ! function inArray(needle, haystack) {
                ! var length = haystack.length;
                ! for(var i = 0; i < length; i++) {
                ! if(haystack _== needle) return true;
                ! }
                ! return false;
                ! }
                ! /
                *
                ! * Gibt zurück, ob die capabilities ein Steuern zulassen
                ! *
                ! * @param array capabilities
                ! * @return boolean
                ! /
                ! function deviceIsControllable(capabilities) {
                ! return (inArray('AUDIO_PLAYER', capabilities)
                ! || inArray('AMAZON_MUSIC', capabilities)
                ! || inArray('TUNE_IN', capabilities));
                ! }
                ! /
                *
                ! * Gibt zurück, ob die capabilities eine Audiowiedergabe zulassen
                ! *
                ! * @param array capabilities
                ! * @return boolean
                ! /
                ! function deviceHasMusicPlayer(capabilities) {
                ! return (inArray('AUDIO_PLAYER', capabilities)
                ! || inArray('AMAZON_MUSIC', capabilities));
                ! }
                ! /
                *
                ! * Gibt zurück, ob die capabilities TuneIn und somit Radio zulassen
                ! *
                ! * @param array capabilities
                ! * @return boolean
                ! /
                ! function deviceHasTuneIn(capabilities) {
                ! return (inArray('TUNE_IN', capabilities));
                ! }
                ! /
                *
                ! * Button wieder auf false zurücksetzen, wenn er true war, danach callback
                ! *
                ! * @param object obj
                ! * @param function callback
                ! /
                ! function unsetButtonFirst(obj, callback) {
                ! if(getState(obj.id).val) {
                ! setState(obj.id,false);
                ! if(callback !== undefined && typeof callback === 'function') callback(obj);
                ! }
                ! }
                ! /
                *
                ! * Liefert str als String zurück, '' anstelle von null, false, …
                ! *
                ! * @param mixed str
                ! * @return string
                ! /
                ! function getStringOrEmpty(str){
                ! return (String(str) !== 'undefined') ? String(str) : '';
                ! }
                ! /
                *
                ! * Liefert das Device anhand der seriennummer
                ! *
                ! * @param string serialNumber
                ! * @param object
                ! /
                ! function getDeviceNameBySerialNumber(serialNumber) {
                ! for (device in devices) {
                ! if (devices[device].serialNumber == serialNumber) {
                ! return device;
                ! }
                ! }
                ! return null;
                ! }
                ! /
                *
                ! * Liefert das erste Device das einen MusicPlayer hat,
                ! * oder null, wenn es keines gibt
                ! *
                ! * @return object|null
                ! /
                ! function getEchoWithMusicPlayerFromDevices() {
                ! for (device in devices) {
                ! if (deviceHasMusicPlayer(devices[device].capabilities)) {
                ! return devices[device];
                ! }
                ! }
                ! return null;
                ! }
                ! /
                *
                ! * Liefert einen bereinigten Namen um daraus einen State-Pfad zu erzeugen
                ! *
                ! * @param string name
                ! * @return string
                ! /
                ! function clearName(name){
                ! name = umlaut(name);
                ! name = name.replace(/\W/g,"_");
                ! return name;
                ! }
                ! /
                *
                ! * Ersetzt Umlaufe/Sonderzeichen
                ! *
                ! * @param string str
                ! * @return string
                ! /
                ! function umlaut(str) {
                ! return str
                ! .replace(/Â|À|Å|Ã/g, "A")
                ! .replace(/â|à|å|ã/g, "a")
                ! .replace(/Ä/g, "AE")
                ! .replace(/ä/g, "ae")
                ! .replace(/Ç/g, "C")
                ! .replace(/ç/g, "c")
                ! .replace(/É|Ê|È|Ë/g, "E")
                ! .replace(/é|ê|è|ë/g, "e")
                ! .replace(/Ó|Ô|Ò|Õ|Ø/g, "O")
                ! .replace(/ó|ô|ò|õ/g, "o")
                ! .replace(/Ö/g, "OE")
                ! .replace(/ö/g, "oe")
                ! .replace(/Š/g, "S")
                ! .replace(/š/g, "s")
                ! .replace(/ß/g, "ss")
                ! .replace(/Ú|Û|Ù/g, "U")
                ! .replace(/ú|û|ù/g, "u")
                ! .replace(/Ü/g, "UE")
                ! .replace(/ü/g, "ue")
                ! .replace(/Ý|Ÿ/g, "Y")
                ! .replace(/ý|ÿ/g, "y")
                ! .replace(/Ž/g, "Z")
                ! .replace(/ž/, "z");
                ! }
                ! /
                *
                ! * Liefert einen String zum http-Status
                ! *
                ! * @param integer status
                ! * @return string
                ! /
                ! function statusCode(status) {
                ! if(status === 0) return "
                * Daten unvollständig ** (csrf fehlt/falsch? Cookie falsch?)";
                ! if(status == 200) return "** OK ";
                ! if(status == 302) return "
                Found (Moved Temporarily) ** (Cookie abgelaufen?)";
                ! if(status == 401) return "** Unauthorized ** (Cookie nicht richtig gesetzt?)";
                ! if(status == 403) return "** Forbidden ** (Kombination Cookie, deviceType, Seriennummer richtig?)";
                ! if(status == 404) return "** Not Found ** (Kommando im Kontext des Geräts sinnvoll?)";
                ! if(status == 500) return "** Internal Server Error** (ggf. Kommando im falschen Kontext verwendet?)";
                ! return "Fehler";
                ! }
                ! /**
                ! * Liefert einen String zum deviceType
                ! *
                ! * @param integer deviceType
                ! * @return string
                ! /
                ! function deviceTypeStr(deviceType){
                ! if(!knownDeviceType[deviceType] || knownDeviceType[deviceType] === undefined) return "Gerät unbekannt";
                ! return knownDeviceType[deviceType];
                ! }
                ! /
                *
                ! * Konvertiert eine Sekundenzahl in einen String im Format (HH:)MM:SS
                ! *
                ! * @param integer sek
                ! * @return string
                ! */
                ! function sekToHMS(sek) {
                ! if (sek === 0) {
                ! return '0';
                ! }
                ! var sec_num = parseInt(sek, 10);
                ! var hours = Math.floor(sec_num / 3600);
                ! var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
                ! var seconds = sec_num - (hours * 3600) - (minutes * 60);
                ! if (minutes < 10) {minutes = "0"+minutes;}
                ! if (seconds < 10) {seconds = "0"+seconds;}
                ! if (hours === 0) {
                ! return minutes+':'+seconds;
                ! }
                ! if (hours < 10) {hours = "0"+hours;}
                ! return hours+':'+minutes+':'+seconds;
                ! }___________________________ _____________z.Beispiel was bedeuten die Zahlen am Ende von dem Fehler. Ist die Zeile von der Error im Script auftritt ?

                y controller[0]: at IncomingMessage. <anonymous>(script.js.Alexa_Device_Command:214:81)

                Caught 2018-06-12 20:38:20.461 error by controller[0]: at dpAbfrageAlexaAnlegen (script.js.Alexa_Device_Command:245:32)

                Caught 2018-06-12 20:38:20.461 error by controller[0]: at Object.parse (native)

                Caught 2018-06-12 20:38:20.461 error by controller[0]: SyntaxError: Unexpected end of JSON input</anonymous>_____________

                MyMeyer

                >>> Hardware: Intel I5 mit ****Debian ProxMox OS: Debian **** <<< >>> Network with UniFi <<<
                >>> HomeMatic CCU-2 (Wired und Funk) / Philips HUE / Echo.DOT / Echo.SHOW / Xiaomi Smart-Home / Xiaomi Robot Vacuum Cleaner / Synology DS 918+ / Shelly 1&2 <<<

                1 Antwort Letzte Antwort
                0
                Antworten
                • In einem neuen Thema antworten
                Anmelden zum Antworten
                • Älteste zuerst
                • Neuste zuerst
                • Meiste Stimmen


                Support us

                ioBroker
                Community Adapters
                Donate

                748

                Online

                32.5k

                Benutzer

                81.7k

                Themen

                1.3m

                Beiträge
                Community
                Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                ioBroker Community 2014-2025
                logo
                • Anmelden

                • Du hast noch kein Konto? Registrieren

                • Anmelden oder registrieren, um zu suchen
                • Erster Beitrag
                  Letzter Beitrag
                0
                • Home
                • Aktuell
                • Tags
                • Ungelesen 0
                • Kategorien
                • Unreplied
                • Beliebt
                • GitHub
                • Docu
                • Hilfe