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

  1. ioBroker Community Home
  2. Deutsch
  3. Cloud Dienste
  4. [SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

NEWS

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

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    1.9k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    15
    1
    2.4k

[SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

Geplant Angeheftet Gesperrt Verschoben Cloud Dienste
261 Beiträge 82 Kommentatoren 94.2k 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.
  • H Offline
    H Offline
    Hauke
    schrieb am zuletzt editiert von
    #124

    Moinsen,

    hatte die Woche leider keine Zeit zu Hause am PC die Fragen zu beantworten.

    @Nikoxx:

    Hi,

    sehr cooles Script. Leider wirft es mir Fehler aus.

    Eine Idee wo dran es liegen könnte ?

    Gruß Niko `

    Fehler sollte nun behoben sein.

    <u>Hier das neue Script</u>:

    ! ```
    `// 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?f=37&t=9237&p=98626&hilit=alexaLogOn#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 = false;
    ! // 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.AlexaLogon.cookie";
    var idCsrf = "javascript.0.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?startTime=&size=20&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[i].creationTimestamp > creationTime) || creationTime === null) {
    deviceName = getDeviceNameBySerialNumber(activities[i].sourceDeviceIds[0].serialNumber);
    setState(pfad + ".History.creationTime", activities[i].creationTimestamp);
    setState(pfad + ".History.deviceName", deviceName);
    setState(pfad + ".History.summary", JSON.parse(activities[i].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[i].serialNumber){
    				logError('Das Geraet "' + clearName(alexaDeviceObj.devices[i].accountName) + '" hat nach update eine andere Seriennummer!');
    			} else {
    
    				var devicePath = deviceObjectPath + clearName(alexaDeviceObj.devices[i].accountName) + ".device";
    
    				httpsReqGet(
    					'/api/device-wifi-details?deviceSerialNumber=' + alexaDeviceObj.devices[i].serialNumber + '&deviceType=' + alexaDeviceObj.devices[i].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[i].language));
    				setState(devicePath + ".online",			alexaDeviceObj.devices[i].online);
    				setState(devicePath + ".parentClusters",	getStringOrEmpty(alexaDeviceObj.devices[i].parentClusters));
    				setState(devicePath + ".softwareVersion",	getStringOrEmpty(alexaDeviceObj.devices[i].softwareVersion));
    
    				// Device updaten
    				updateDevice(clearName(alexaDeviceObj.devices[i].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[i].capabilities)) {		
    			devices[clearName(alexaDeviceObj.devices[i].accountName)] = createDevice(alexaDeviceObj.devices[i], 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[i] == 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;
    

    }`[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]

    mfg Hauke

    1 Antwort Letzte Antwort
    0
    • H Offline
      H Offline
      Hauke
      schrieb am zuletzt editiert von
      #125

      Da in einem Beitrag sonst zu viele Zeichen wären, hier mein Widget-Export:

      ! [{"tpl":"tplFrame","data":{"g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"title":"Echo Küche","title_color":"#ffffff","title_top":"0","title_left":"0","header_height":"19","header_color":"#2399e1","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"154px","top":"50px","border-width":"3px","border-style":"solid","border-color":"#2399e1","width":"276px","height":"488px","color":"#ffffff","font-size":"","z-index":1},"widgetSet":"basic"},{"tpl":"tplImage","data":{"g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","refreshInterval":"0","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/amazon-echo-dot-smart-lautsprecher-schwarz.png","stretch":false},"style":{"left":"161px","top":"78px","width":"63px","height":"62px","z-index":2},"widgetSet":"basic"},{"tpl":"tplJquiSlider","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.volume","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"min":"0","max":"100","step":"5","lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0},"style":{"left":"165px","top":"315px","color":"#2399e1","width":"250px","height":"23px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.play","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/icons-ultimate-png/981.png","value":"1"},"style":{"left":"230px","top":"238px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.pause","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/icons-ultimate-png/983.png","value":"1"},"style":{"left":"299px","top":"239px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.previous","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/icons-ultimate-png/987.png","value":"1"},"style":{"left":"160px","top":"238px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.next","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/icons-ultimate-png/988.png","value":"1"},"style":{"left":"369px","top":"238px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplMfdSocketCtrl","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.shuffle","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","asButton":"true","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"icon_off":"/vis.0/test/img/shuffle_off.png","icon_on":"/vis.0/test/img/shuffle_on.png","invert_state":false},"style":{"left":"160px","top":"170px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui-mfd"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioHH-s18018.png","value":"s18018"},"style":{"left":"163px","top":"409px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioSchlagerparadies-s80428.png","value":"s80428"},"style":{"left":"233px","top":"409px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioSSL-s10637.png","value":"s10637"},"style":{"left":"302px","top":"409px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioAlster-s24926.jpg","value":"s24926"},"style":{"left":"372px","top":"409px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioRSH-1024-s18353.png","value":"s18353"},"style":{"left":"372px","top":"480px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioNDR-1-Welle-Nord-s25044.png","value":"s25044"},"style":{"left":"302px","top":"480px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioDelta-s85114.png","value":"s85114"},"style":{"left":"233px","top":"480px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplIconState","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.tunein","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"src":"/vis.0/test/img/radioEnergy-s6637.jpg","value":"s6637"},"style":{"left":"163px","top":"480px","width":"55px","height":"55px","z-index":6},"widgetSet":"jqui"},{"tpl":"tplJquiRadioSteps","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.volume","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"min":"0","max":"100"},"style":{"left":"165px","top":"360px","font-size":"10.6px","font-weight":"normal","width":"258px","text-align":"center","z-index":6},"widgetSet":"jqui"},{"tpl":"tplValueBoolCtrl","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.device.online","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"html_false":"Offline","html_true":"Online","visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"353px","top":"53px","color":"#ffffff","width":"77px","height":"17px","text-align":"right","z-index":2},"widgetSet":"basic"},{"tpl":"tplJquiSelectList","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.control.playlistId","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"values":"{javascript.0.AlexaControl.Playlists.IDs}","texts":"{javascript.0.AlexaControl.Playlists.Titles}","height":"100","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"no_style":false,"open":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"231px","top":"200px","width":"193px","height":"25px","z-index":"10"},"widgetSet":"jqui"},{"tpl":"tplHtml","data":{"g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","refreshInterval":"0","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"html":"Playlists:"},"style":{"left":"232px","top":"173px","width":"192px","height":"23px","color":"#ffffff"},"widgetSet":"basic"},{"tpl":"tplValueString","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.interpreter","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"228px","top":"105px","width":"200px","height":"20px","color":"#ffffff","text-align":"right","font-style":"normal","font-weight":"","font-size":"medium"},"widgetSet":"basic"},{"tpl":"tplValueString","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.title","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"161px","top":"77px","width":"267px","height":"23px","color":"#ffffff","text-align":"right","font-style":"normal","font-weight":"bold","font-size":"large","z-index":"25"},"widgetSet":"basic"},{"tpl":"tplValueStringImg","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.mainArtUrl","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"refreshInterval":"0","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"369px","top":"132px","width":"55px","height":"55px"},"widgetSet":"basic"},{"tpl":"tplValueFloatBar","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaProgressPercent","g_fixed":false,"g_visibility":true,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"min":"0","max":"100","orientation":"horizontal","color":"#2399e1","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"border":"","visibility-cond":">","visibility-val":"0","visibility-groups-action":"hide","visibility-oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaLength"},"style":{"left":"234px","top":"152px","width":"110px","height":"6px","z-index":"25"},"widgetSet":"basic"},{"tpl":"tplValueString","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaProgressStr","g_fixed":false,"g_visibility":true,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":">","visibility-val":"0","visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaProgressStr"},"style":{"left":"235px","top":"132px","color":"#ffffff","width":"59px","height":"14px","text-align":"left","font-style":"normal","font-size":"small"},"widgetSet":"basic"},{"tpl":"tplValueString","data":{"oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaLengthStr","g_fixed":false,"g_visibility":true,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":">","visibility-val":"0","visibility-groups-action":"hide","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"visibility-oid":"javascript.0.AlexaControl.Devices.Kueche.player.mediaLength"},"style":{"left":"301px","top":"132px","color":"#ffffff","width":"43px","height":"14px","text-align":"right","font-style":"normal","font-size":"small"},"widgetSet":"basic"}] !

      Ich habe "ioBroker.icons-ultimate-png" installiert - die anderen Icons zusammengesammelt. Hauptsächlich bei TuneIn.

      Edit:Falsches Widget, durch aktuelles ersetzt

      mfg Hauke

      1 Antwort Letzte Antwort
      0
      • N Offline
        N Offline
        Nikoxx
        schrieb am zuletzt editiert von
        #126

        Fettes Dankeschön :mrgreen: … läuft jetzt !

        1 Antwort Letzte Antwort
        0
        • A Offline
          A Offline
          Arnulf
          schrieb am zuletzt editiert von
          #127

          @Hauke:

          Moinsen,

          hatte die Woche leider keine Zeit zu Hause am PC die Fragen zu beantworten.

          @Nikoxx:

          Hi,

          sehr cooles Script. Leider wirft es mir Fehler aus.

          Eine Idee wo dran es liegen könnte ?

          Gruß Niko `

          Fehler sollte nun behoben sein.

          <u>Hier das neue Script</u>:

          ! ```
          `// 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?f=37&t=9237&p=98626&hilit=alexaLogOn#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 = false;
          ! // 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.AlexaLogon.cookie";
          var idCsrf = "javascript.0.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?startTime=&size=20&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[i].creationTimestamp > creationTime) || creationTime === null) {
          deviceName = getDeviceNameBySerialNumber(activities[i].sourceDeviceIds[0].serialNumber);
          setState(pfad + ".History.creationTime", activities[i].creationTimestamp);
          setState(pfad + ".History.deviceName", deviceName);
          setState(pfad + ".History.summary", JSON.parse(activities[i].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[i].serialNumber){
            			logError('Das Geraet "' + clearName(alexaDeviceObj.devices[i].accountName) + '" hat nach update eine andere Seriennummer!');
            		} else {
            		
            			var devicePath = deviceObjectPath + clearName(alexaDeviceObj.devices[i].accountName) + ".device";
          
            			httpsReqGet(
            				'/api/device-wifi-details?deviceSerialNumber=' + alexaDeviceObj.devices[i].serialNumber + '&deviceType=' + alexaDeviceObj.devices[i].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[i].language));
            			setState(devicePath + ".online",			alexaDeviceObj.devices[i].online);
            			setState(devicePath + ".parentClusters",	getStringOrEmpty(alexaDeviceObj.devices[i].parentClusters));
            			setState(devicePath + ".softwareVersion",	getStringOrEmpty(alexaDeviceObj.devices[i].softwareVersion));
            			
            			// Device updaten
            			updateDevice(clearName(alexaDeviceObj.devices[i].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[i].capabilities)) {		
            		devices[clearName(alexaDeviceObj.devices[i].accountName)] = createDevice(alexaDeviceObj.devices[i], 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[i] == 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;
          

          }`

          ! ich mache da wohl was falsch.
          ! Ich habe die zwei Variablen for Cookie und csrf auf das bei mir gültige Objekt gelegt.
          ! Beim Start bekomme ich den fehler:
          ! cript.js.common.AlexaControl: Cannot use sync getState, use callback instead getState("javascript.0.productive.alexalogon.csrf", function (err, state){}); or disable the "Do not subscribe all states
          ! Disable ich "Do not subscribe all states", läuft das Script zwar weiter, dafür werfen alle anderen Skripte Fehler.
          ! Warum ist diese Option relevant und was macht sie?
          ! Fehlermeldung komplett:
          ! javascript.0 2018-02-23 22:21:29.768 error at ContextifyScript.Script.runInContext (vm.js:35:29)
          ! javascript.0 2018-02-23 22:21:29.767 error at script.js.common.AlexaControl:82:30
          ! javascript.0 2018-02-23 22:21:29.766 error TypeError: Cannot read property 'val' of undefined
          ! javascript.0 2018-02-23 22:21:29.766 error ^
          ! javascript.0 2018-02-23 22:21:29.765 error var csrf = getState(idCsrf).val;
          ! javascript.0 2018-02-23 22:21:29.764 error script.js.common.AlexaControl: script.js.common.AlexaControl:82
          ! javascript.0 2018-02-23 22:21:29.722 error script.js.common.AlexaControl: Cannot use sync getState, use callback instead getState("javascript.0.productive.alexalogon.csrf", function (err, state){}); or disable the "Do not subscribe all states
          ! (bitte beachten: Die Zeilennummern sind 2 höher als das Original, weil ich zwei Zeilen eingefügt hatte (s.o.))[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]
          ``` `

          1 Antwort Letzte Antwort
          0
          • C Offline
            C Offline
            csamaggi
            schrieb am zuletzt editiert von
            #128

            Sehr cooles Skript woher bekomme ich denn die Radiostation ID damit ich die Default von Eins Live ändern kann?

            MFG Maggi

            1 Antwort Letzte Antwort
            0
            • R Offline
              R Offline
              RooftopBBQ
              schrieb am zuletzt editiert von
              #129

              Die findest du auf der Seite von TuneIn.

              Steht als letzte Zahl dann oben im Adressfeld deines Browsers.

              Gruß

              Marcel

              1 Antwort Letzte Antwort
              0
              • C Offline
                C Offline
                csamaggi
                schrieb am zuletzt editiert von
                #130

                Ah Danke, ich stehe vor einem Problem auf das ich keine Lösung finde.

                Wenn ich in der History schaue wird mir das Gerät und auch die Zeit angezsigt.

                Doch bei Befehl nur alexa ohne den Befehl dazu, einmal hat es funktioniert dann nicht mehr.

                Wofür hast du den Abfragebutton drin welche Aufgabe hat der?

                Update: Ah wie es scheint dauert es etwas bis die Rückmeldung in IO erscheint.

                Anfrage: Wäre es möglich die Funktion in das Skript einzubauen das mann die Bluetoothgeräte koppeln und entkoppeln bzw trennen kann. In dem Alexaadapter der nicht offiziell im IO drin ist kann man das machen.

                MFG Maggi

                1 Antwort Letzte Antwort
                0
                • H Offline
                  H Offline
                  Hauke
                  schrieb am zuletzt editiert von
                  #131

                  Nabend,

                  die History zeigt bei mir auch manchmal nur "alexa" an. Im Verlauf auf der Webseite steht aber auch nur "alexa".

                  Über Bluetooth hatte ich schon mal nachgedacht, allerdings noch keine Zeit gehabt, das umzusetzen.

                  Auf meiner ToDo-Liste ist noch folgendes:

                  • Neue Smart-Home Geräte suchen

                    • damit könnte dann per ioBroker Alexa angestoßen werden neue Geräte zu finden
                  • Bluetooth

                    • zum Koppeln der Stereoanlage (mit Dongle) mit dem Dot

                    • zum Koppeln eines Smartphones an den Echo.

                  • Audiogruppen

                    • erstellen

                    • ändern

                  • Bitte nicht stören

                    • an/aus
                  • Prime Music

                    • Playlists und Sender auslesen (wird wohl zu viele geben, um das sinnvol zu machen)
                  • Warteschlange/Verlauf anzeigen

                    • hatte damit schon mal rumgespielt, es aber erstmal verworfen, da recht umständlich

                  Theoretisch sind alle einstellungen über die Webseite auch per Skript möglich - wird halt nur sehr aufwendig…

                  mfg Hauke

                  1 Antwort Letzte Antwort
                  0
                  • C Offline
                    C Offline
                    csamaggi
                    schrieb am zuletzt editiert von
                    #132

                    Ah danke Hauke für die Infos.

                    Da hätte ich direkt noch eine Frage ist es eigentlich auch möglich die Einkaufsliste auszulesen und zu bearbeiten?

                    MFG Maggi

                    1 Antwort Letzte Antwort
                    0
                    • thexbrainT Offline
                      thexbrainT Offline
                      thexbrain
                      schrieb am zuletzt editiert von
                      #133

                      Bin irgendwie zu blöd die Tuneln ID in Vis einzufügen.

                      Ich habe das Script von Hauke.

                      Wo muss ich den Radiosender eintragen??

                      Gefunden habe ich die Sender Id soweit.

                      1 Antwort Letzte Antwort
                      0
                      • C Offline
                        C Offline
                        csamaggi
                        schrieb am zuletzt editiert von
                        #134

                        Was genau möchtest du denn machen nur den Defaultsender oder mehrere anlegen damit du sie dann auswählen kannst?

                        MFG Maggi

                        1 Antwort Letzte Antwort
                        0
                        • R Offline
                          R Offline
                          RooftopBBQ
                          schrieb am zuletzt editiert von
                          #135

                          @csamaggi Mit dem Widget "jqui - Ctrl Icon state" geht das.
                          5480_01.png

                          Da gibt man dann die StationID unter "Wert" ein.
                          5480_02.png

                          Gruß

                          Marcel

                          1 Antwort Letzte Antwort
                          0
                          • B Offline
                            B Offline
                            Buhu91
                            schrieb am zuletzt editiert von
                            #136

                            @Hauke:

                            Nabend,

                            die History zeigt bei mir auch manchmal nur "alexa" an. Im Verlauf auf der Webseite steht aber auch nur "alexa".

                            Über Bluetooth hatte ich schon mal nachgedacht, allerdings noch keine Zeit gehabt, das umzusetzen.

                            Auf meiner ToDo-Liste ist noch folgendes:

                            • Neue Smart-Home Geräte suchen
                              • damit könnte dann per ioBroker Alexa angestoßen werden neue Geräte zu finden
                                … `

                            Wäre es damit Möglich Geräte über den Echo Plus hinzuzufügen und über den IO broker zu steuern?

                            HomeMatic, MiHome, Yeelight, Wifi light, G-Homa, Osram Smart+, Hue, Sonoff

                            1 Antwort Letzte Antwort
                            0
                            • C Offline
                              C Offline
                              csamaggi
                              schrieb am zuletzt editiert von
                              #137

                              Damit ist gemeint wenn du neuen Smartgeräte in Io anlegst also im cloud Adapter dieses dann zu suchen.

                              Derzeit musst du dazu ja noch in die Alexaapp gegen oder Alexa per Sprachbefehl dazu auffordern nach neuen Geräte zu suchen, dies könnte man dann eben über IoBroker regeln.

                              MFG Maggi

                              1 Antwort Letzte Antwort
                              0
                              • M Offline
                                M Offline
                                ManuelW
                                schrieb am zuletzt editiert von
                                #138

                                Hallo zusammen,

                                wo finde ich das Script? Hier im Thread konnte ich es nicht entdecken, aber im Forum scheinen grad so einige Beiträge zu fehlen.

                                1 Antwort Letzte Antwort
                                0
                                • E Offline
                                  E Offline
                                  Erti1337
                                  schrieb am zuletzt editiert von
                                  #139

                                  Kann es sein, das es seit gestern nicht mehr geht ?

                                  Wenn ich z.b den play button nutze unter Objekte im Device BAD z.b dann kommt immer :

                                  ! javascript.0 2018-03-04 05:25:44.008 warn script.js.common.Alexa_Remote_Control: Alexa Volume: keine Lautstärke angegeben. Parameter fehlt.
                                  ! javascript.0 2018-03-04 05:25:43.762 info script.js.common.Alexa_Remote_Control: [updateDevice] Bad
                                  ! javascript.0 2018-03-04 05:25:40.760 warn script.js.common.Alexa_Remote_Control: HEADERS: {"server":"Server","date":"Sun, 04 Mar 2018 04:25:40 GMT","content-type":"application/json","content-length":"16","connection":"close","x-amzn-requesti
                                  ! javascript.0 2018-03-04 05:25:40.760 warn script.js.common.Alexa_Remote_Control: Gesendetes Kommando: {"type":"PlayCommand"}
                                  ! javascript.0 2018-03-04 05:25:40.759 warn script.js.common.Alexa_Remote_Control: Negative Rückmeldung von Alexa: 400: Fehler
                                  ! javascript.0 2018-03-04 05:25:40.415 info script.js.common.Alexa_Remote_Control: [httpsPostCmd] Device: Bad - Kommando: {"type":"PlayCommand"}

                                  Ich hab aber noch nie nen Volume Parameter mitgegeben ^^

                                  Grüß

                                  Erti

                                  1 Antwort Letzte Antwort
                                  0
                                  • BBTownB Offline
                                    BBTownB Offline
                                    BBTown
                                    schrieb am zuletzt editiert von
                                    #140

                                    @ManuelW:

                                    wo finde ich das Script? ` im ersten Beitrag
                                    @ManuelW:

                                    … aber im Forum scheinen grad so einige Beiträge zu fehlen. ` du hast recht, sie scheinen nun aber wieder da zu sein

                                    ioBroker auf NUC (VM debian v13 (Trixie ), node v22.21.0 npm v10.9.4, js-controller v7.0.7 jsonl/jsonl / HomeMatic CCU-2 (Wired und Funk) / Philips HUE / echo.DOT / Broadlink RM pro / SONOS

                                    1 Antwort Letzte Antwort
                                    0
                                    • HomoranH Nicht stören
                                      HomoranH Nicht stören
                                      Homoran
                                      Global Moderator Administrators
                                      schrieb am zuletzt editiert von
                                      #141

                                      siehe:

                                      http://forum.iobroker.net/viewtopic.php?f=8&t=12314

                                      Gruß

                                      Rainer

                                      kein Support per PN! - Fragen im Forum stellen - es gibt fast nichts, was nicht auch für andere interessant ist.

                                      Benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.

                                      der Installationsfixer: curl -fsL https://iobroker.net/fix.sh | bash -

                                      1 Antwort Letzte Antwort
                                      0
                                      • E Offline
                                        E Offline
                                        Erti1337
                                        schrieb am zuletzt editiert von
                                        #142

                                        Das war aber nicht auf mich bezogen oder ? :)

                                        Also bei mir geht seit einem TAG kein remote Alexa mehr.

                                        Skript neustart , Alexa neustart, alles hinter mir.

                                        Wenn ich Objekt Play button nutze bekomme ich Fehler 400 ^^

                                        Gehts bei irgendwem aktuell ?

                                        1 Antwort Letzte Antwort
                                        0
                                        • C Offline
                                          C Offline
                                          csamaggi
                                          schrieb am zuletzt editiert von
                                          #143

                                          Habe es eben mal probiert es läuft fast ohne Probleme.

                                          Beim ersten ausführen bekam ich Fehler 404 danach lief es dann aber.

                                          MFG Maggi

                                          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
                                          FAQ Cloud / IOT
                                          HowTo: Node.js-Update
                                          HowTo: Backup/Restore
                                          Downloads
                                          BLOG

                                          730

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          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