NEWS
Seit dem Javascript Adapter Update –-Fehlermeldung
-
Hallo
Ich habe gestern beim Javascript Adapter ein Update gemacht und bekomme beim starten des Scripts folgende Fehlermeldung:
–------------------------------------------------------------------------------------------------------------------------------
14:38:34.369 [error] javascript.0 SyntaxError: Unexpected end of JSON input at Object.parse (native) at dpAbfrageAlexaAnlegen (script.js.common.Alexa.Skript1(1):207:32) at IncomingMessage. (script.js.common.Alexa.Skript1(1):176:81) at emitNone (events.js:91:20) at IncomingMessage.emit (events.js:185:7) at endReadableNT (_stream_readable.js:974:12) at _combinedTickCallback (internal/process/next_tick.js:80:11) at process._tickCallback (internal/process/next_tick.js:104:9)
14:38:34.486 [error] Caught by controller[0]: at dpAbfrageAlexaAnlegen (script.js.common.Alexa.Skript1(1):207:32)
14:38:34.487 [error] Caught by controller[0]: at IncomingMessage. (script.js.common.Alexa.Skript1(1):176:81)
–-------------------------------------------------------------------------------------------------------------------------------
Kann jemand mir weiter helfen ? Vor dem Update war alles gut.
-
Da stimmt was mit dem Json input nicht.. Steht doch da.. :roll: :lol:
Wäre hilfreich wenn du das entsprechende Script zeigen würdest..
Gruß
-
Da stimmt was mit dem Json input nicht.. Steht doch da.. :roll: :lol:
Wäre hilfreich wenn du das entsprechende Script zeigen würdest..
Gruß `
Hallo
also hier ist das Script welches ermöglicht Alexa anzusteuern.
! ```
`// Alexa mit Javaskript in ioBroker steuern
// Skript arbeitet unabhängig vom Cloud Adapter
// Version: v0.3.1
// -----------------------------------------------------------------------------
// alexaCommand("arbeitszimmer","volume",70); // Alle Anwendungen
// alexaCommand("arbeitszimmer","pause"); // Radio, Spotify, Hörbücher
// alexaCommand("arbeitszimmer","play"); // Radio, Spotify, Hörbücher
// alexaCommand("arbeitszimmer","next"); // z.B. Spotify: nächstes Lied
// alexaCommand("arbeitszimmer","previous"); // z.B. Spotify: vorheriges Lied
// alexaCommand("arbeitszimmer","forward"); // z.B. Hörbücher: 30 Sekunden vor
// alexaCommand("arbeitszimmer","rewind"); // z.B. Hörbücher: 30 Sekunden zurück
// alexaCommand("arbeitszimmer","shuffle",true); // z.B Amazon Music, Shuffle ein in der aktuellen Playlist
// alexaCommand("arbeitszimmer","shuffle",false); // z.B Amazon Music, Shuffle aus in der aktuellen Playlist
// alexaCommand("arbeitszimmer","radio",true); // schaltet den Default tunein Radiosender an
// alexaCommand("arbeitszimmer","radio",false); // setzt Radio auf Pause
// alexaCommand("arbeitszimmer","tunein","s100198"); // setzt tunein Radio auf "s100198" (Einslive)// EINRICHTUNG:
// 1. cURL extrahieren, siehe
// https://www.gehrig.info/alexa/Alexa.html
//
// benötigt wird:
// je Gerät: deviceType, deviceSerialNumber
// einmalig: csrf, cookie
//
// Der Cookie muss aus dem Trace mit tunein entnommen werden, damit er sowohl mit den Kommandos,
// als auch mit der Radistation funktioniert. Es ist ein sehr langer String
// alles von: x-amzn-dat-gui-client
// bis alles vor dem nächsten -H// ----------------------------------------
// Infos und Resourcen zum Skript:
// Webseiten/URLs Request mit Fehlerbehandlung, siehe:
// http://forum.iobroker.net/viewtopic.php?f=21&t=4259&p=40890&hilit=request#p40880
// Alexa Steuerskripte:
// https://github.com/thorsten-gehrig/alexa-remote-control// ---------------------------------------
// Tunein Radiosender:
// http://tunein.com/radio/Antenne-Düsseldorf-1042-s25772/
// s25772 -> Antenne Düsseldorf// Liste einiger Sender:
// s25772 -> Antenne Düsseldorf
// s100198 -> Einslive
// s100183 -> WDR2 Rheinland
// s8007 -> Hitradio Ö3// ---------------------------------------
// Changelog:// 0.3.1 Fehlerkorrekturen
// 0.3.0 alle createState() mit Callback
// 0.2.0 Redesigne. Ale bekannten Alexa-Geräte werden nun ausgelesen. Keine manuelle Pflege nötig.
// (nur noch der Cookie und csrf müssen ausgelesen werden)
// 0.1.2 mediaOwnerCustomerId vom Skriptbereich in den individuellen Konfigurationsbereich verlegt// ---------------------------------------
// TODOs:// GET: fragt aktuellen Titel ab:
// path: '/api/np/queue?deviceSerialNumber=xxxxxxxx&deviceType=xxxxxxxxx',// GET: fragt viele Statusinfo ab (Titel, Status, Volume, Muted, ...):
// path: '/api/media/state?deviceSerialNumber=xxxxxxxxxxxxx&deviceType=xxxxxxxxxx',// prüfen: Authentifizierung mit User/PW möglich? Erhaltenen Cookie dann für die weitere Verwendung speichern
// prüfen: Statusänderungen abonieren?
// Alexa Objekt als Sicherung in DP ablegen
// deviceSerialNumber aus dem Array Echos auch als Datenpunkt anlegen
// ---------------------------------------
// bekannte Probleme:// ein ungültiger Cookie lässt das Skript unter Umständen abstürzen
// Skriptverhalten:
var logOn = true; // Skript Logausgabe ein- (true) / ausschalten (false). Fehler werden unabhängig von dieser Einstellung ausgegeben.
var forecreation = false; // true: Datenpunkte werden überschrieben (wenn z.B. Bezeichnungen geändert wurden)var pfad = "alexa_device_command" +"."; // Pfad im Javascript-Adapter unter dem die Geräte angelegt werden sollen
var defaultRadiostation = "s25111"; // Radioeins vom rbb - Default Radiostation für den Radio an Button.
// Individuelle Daten, per Chrome Debug ermitteln, siehe Link in der Beschreibung oben:
var csrf = 'xxxxxxxxxxx';
// cookie gilt für alle Devices
var cookie = 'xxxxcookie';// Liste der bekannten Devicetypen, Geräte mit bekannten DeviceType und "anlegen":true werden mit Steuermöglichkeit mit steuerbaren Datenpunkten angelegt
// hier muss nur was angepasst werden, wenn für andere Geräte auch Steuerdatenpunkte angelegt werden sollen
// oder wenn es ein Geröte gibt, welches hier nicht gepflegt ist
var knownDeviceType = {
"A3S5BH2HU6VAYF": {"device":"Echo Dot 2.Gen", "anlegen": true},
"AB72C64C86AW2": {"device":"Echo ", "anlegen": true},
"A10A33FOX2NUBK": {"device":"Spot ", "anlegen": true},
"A2E0SNTXJVT7WK": {"device":"Fire TV V1", "anlegen": false},
"ADVBD696BHNV5": {"device":"Fire TV Stick V1", "anlegen": false},
"A2T0P32DY3F7VB": {"device":"echosim.io", "anlegen": false},
"AILBSA2LNTOYL": {"device":"reverb App", "anlegen": false}!
};// -----------------------------------------------------------------------------
// ------------ Skript, ab hier nichts ändern --------------
// -----------------------------------------------------------------------------var devicePfad = pfad + "devices" + "."; // Pfad unter dem die zu steuernden Geräte angelegt werden
var otherDevicePfad = pfad + "other_devices" + "."; // Pfad unter dem dievar mediaOwnerCustomerId; // CUSTOMERID wird aus der Geräteliste ausgelesen
var alexaDeviceObj = {}; // globales Objekt mit den Devices von Alexa abgefragt
var echos = {}; // globales Objekt echos mit allen zu steuernden Echos (echos = {"arbeitszimmer":{"deviceSerialNumber": "XXXXXXX", "deviceType":"A3S5BH2HU6VAYF"},...)var https = require('https'); // Node Module https verwenden
var ok = true;
function setOptions(path,method) { // setzt die Options für den http/https Request
var options = {
host: 'layla.amazon.de',
path: path,
method: method,
timeout:10000,
headers: {
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
'Content-Type': 'text/plain',
'csrf' : csrf,
'Cookie' : cookie
}
};
return options;
}function httpsReqGet(path,callback) {
if(logOn) log("Abfrage " + path + " an Alexa gesendet");
options = setOptions(path,"GET");
log("hallo");
var req = https.get(options, function getDevices(res) {
log("Du");
if(logOn) log('STATUS: ' + res.statusCode) + ": " + statusCode(res.statusCode); // Statuscode
if(logOn) log('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
var chunkLine = 0;res.on('data', function(chunk) { chunkLine = chunkLine + 1; // Hier können die einzelnen Zeilen verarbeitet werden... //if(logOn) log("Zeilennummer: " + chunkLine+ " ,Inhalt: " + chunk); bodyChunks.push(chunk); }).on('end', function() { //if(logOn) log("ARRAY mit den einzelnen Zeilen: " + bodyChunks); //if(logOn) log("ARRAY Länge: " + bodyChunks.length); var body = Buffer.concat(bodyChunks); // ...und/oder das Gesamtergebnis (body). if(!body) log("keine Daten erhalten","warn"); if(logOn) log('BODY: ' + body); if(callback !== undefined && typeof callback === 'function') return callback(null, body, dpAnlegen); ok = false; log("kein gültiger Callback angegeben","warn"); return log(body,"warn"); }); }); req.on('error', function(e) { // Fehler abfangen log('ERROR: ' + e.message,"warn"); if(callback !== undefined && typeof callback === 'function') return callback(e.message, null); log("keinen gültigen Callback gefunden","warn"); ok = false; return log("error: " + e.message,"warn"); }); req.end();
}
function dpAbfrageAlexaAnlegen (err,result,callback) {
if (err) {
log("Abfrage der bekannten Devices bei Alexa mit Fehler","warn");
log("Error: " + err);
ok = false;
return log("Automatisches Anlegen/Aktualisieren von Datenpunkten mit Fehler abgebrochen","warn");
}
//TODO: Test (im if darüber: wenn error, dann prüfen, ob alte Daten vorhanden sind und diese laden: alexaDeviceObj & mediaOwnerCustomerId)
//log("###############: "+ getState(pfad+"_alexaDeviceObj").val);if(!result) return log("Es konnten keine Daten ermittelt werden! Cookie richtig?","warn"); if(logOn) log(result); alexaDeviceObj = JSON.parse(result); createState(pfad + "_alexaDeviceObj", JSON.stringify(alexaDeviceObj), true, {name:"Object mit allen Devices", type:"string", role:"value"}); var numberOfDevices = alexaDeviceObj.devices.length; if(logOn) log("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices); if (numberOfDevices < 1) { ok = false; return log("Error: Skript konnte keine Geräte abfragen","warn"); } mediaOwnerCustomerId = alexaDeviceObj.devices[0].deviceOwnerCustomerId; // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben createState(pfad + "_mediaOwnerCustomerId", mediaOwnerCustomerId, forecreation, {name:"Individuelle Kunden ID", type:"string", role:"value"}); var device; var dpName; for(var i = 0; i < numberOfDevices; i++) { device = alexaDeviceObj.devices[i].accountName; dpName = clearName(alexaDeviceObj.devices[i].accountName); log("Gerät " + i + ": " + device+" - Datenpunktname: " + dpName); alexaDeviceObj.devices[i].dpName = dpName; if(typeof(knownDeviceType[alexaDeviceObj.devices[i].deviceType]) != "undefined") { alexaDeviceObj.devices[i].anlegen = knownDeviceType[alexaDeviceObj.devices[i].deviceType].anlegen; } else { alexaDeviceObj.devices[i].anlegen = false; log(device + " : Gerätetyp ("+alexaDeviceObj.devices[i].deviceType+") unbekannt. Keine Steuerungsmöglichkeiten angelegt","warn"); } //log(alexaDeviceObj.devices[i].anlegen); } if(logOn) log("deviceOwnerCustomerId: " + mediaOwnerCustomerId); if(callback !== undefined && typeof callback === 'function') { return null, callback(); // !!! weiter zu dpAnlegen } log("kein Callback"); return log("Skriptfehler: error: kein Callback","warn");
}
function createStates(arr, func, cb) {
var doneCounter = 0;
arr.forEach(function alleDpBearbeiten(obj) {
func(obj.name, obj.initialValue, obj.forceCreation, obj.common, function () {
doneCounter += 1;
//if(logOn) log(doneCounter+": " + obj.name+" mit Wert: " + obj.initialValue + " ("+obj.common.type+") angelegt");
if (doneCounter === arr.length) {
cb(); // mit der Funktion (callback) geht es weiter, wenn alles erledigt ist
}
});
});
}function createStateObj(arr,name,initialValue,forceCreation,common){
var obj = {
"name":name,
"initialValue":initialValue,
"forceCreation":forceCreation,
"common":common
};
return arr.push(obj);
}function createStatesReady() {
log("--- Alexa Kommandos - Datenpunkte angelegt ---");
//setOn();
setTimeout(setOn, 3000);
}function dpAnlegen() {
var dfSt = defaultRadiostation;
var fc = forecreation; //forecreation;
var deviceType,essid,macAddress,swVersion,deviceTypeTxt,capabilities;
var echo;
var dpArr = [];
// for (var echo in echos) {
for(var i = 0; i < alexaDeviceObj.devices.length; i++) {
var pfad = otherDevicePfad;
echo = alexaDeviceObj.devices[i].dpName;
if(alexaDeviceObj.devices[i].anlegen) {
pfad = devicePfad;
echos[echo] = {"deviceType":alexaDeviceObj.devices[i].deviceType,"deviceSerialNumber":alexaDeviceObj.devices[i].serialNumber};
createStateObj(dpArr,pfad + echo +".volume", 40, false, {name:"Volume (0-100)", type:"number", role:"control.value"});
createStateObj(dpArr,pfad + echo +".pause", false, fc, {name:"Pause", type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".play", false, fc, {name:"Play", type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".next", false, fc, {name:"Next (nächster Titel)", type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".previous", false, fc, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".forward", false, fc, {name:"Forward (Hörbuch 30 Sekunden vor)", type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".rewind", false, fc, {name:"Rewind (Hörbuch 30 Sekunden zurück)",type:"boolean", role:"button"});
createStateObj(dpArr,pfad + echo +".shuffle", false, fc, {name:"Shuffel an/aus (true/false)", type:"boolean", role:"switch"});
createStateObj(dpArr,pfad + echo +".Last_Status","init", fc, {name:"Letzter Status", type:"string", role:"value"});
createStateObj(dpArr,pfad + echo +".radio", false, fc, {name:"Default Radiostation an/aus", type:"boolean", role:"switch"});
createStateObj(dpArr,pfad + echo +".tunein", dfSt, fc, {name:"tunein Radiosenderkennung", type:"string", role:"control.value"});
}
essid = alexaDeviceObj.devices[i].essid;
macAddress = alexaDeviceObj.devices[i].macAddress;
swVersion = alexaDeviceObj.devices[i].softwareVersion;
deviceTypeTxt = deviceTypeStr(alexaDeviceObj.devices[i].deviceType);
deviceType = alexaDeviceObj.devices[i].deviceType;
capabilities = JSON.stringify(alexaDeviceObj.devices[i].capabilities);createStateObj(dpArr,pfad + echo +"._info.device_type_str", deviceTypeTxt, true, {name:"Amazon Echo Typ", type:"string", role:"value"}); createStateObj(dpArr,pfad + echo +"._info.device_type", deviceType, fc, {name:"Amazon Echo deviceType", type:"string", role:"value"}); createStateObj(dpArr,pfad + echo +"._info.essid", essid, true, {name:"SSID des WLANs", type:"string", role:"value"}); createStateObj(dpArr,pfad + echo +"._info.macAddress", macAddress, fc, {name:"MAc-Adresse des Echos", type:"string", role:"value"}); createStateObj(dpArr,pfad + echo +"._info.softwareVersion", swVersion, true, {name:"Softwareversion des Echos", type:"string", role:"value"}); createStateObj(dpArr,pfad + echo +"._info.capabilities", capabilities, true, {name:"Fähigkeiten des Echos", type:"string", role:"value"}); } if(logOn) log("Anzahl der anzulegenden Datenpunkte: " + dpArr.length); createStates(dpArr, createState, createStatesReady);
}
function clearName(name){ // Sonderzeichen gegen Unterstrich ersetzen
name = umlaut(name);
name = name.replace(/\W/g,"_");
return name;
}function httpsReqCmd(device,data) { // schickt an ein Alexa-Gerät (device) ein Kommando (data) per https-Request / Daten im Body
if(logOn) log("Kommando: " + data);
// Seriennummer und Gerätetyp anhand der Device-Bezeichnung ermitteln
var deviceSerialNumber = echos[device].deviceSerialNumber;
var deviceType = echos[device].deviceType;
var path = '/api/np/command?deviceSerialNumber='+deviceSerialNumber+'&deviceType='+deviceType;
if(JSON.parse(data).type == "tunein") {
var guideId = JSON.parse(data).station;
// path setzt eine Radiostation
path = '/api/tunein/queue-and-play?deviceSerialNumber='+deviceSerialNumber+'&deviceType='+deviceType+'&guideId='+guideId+'&contentType=station&callSign=&mediaOwnerCustomerId='+mediaOwnerCustomerId;
}
var options = setOptions(path,"POST");// https Request für Alexa Kommandos: var req = https.request(options, function(res) { if(logOn) log("Geräteyp: " + deviceTypeStr(deviceType)); // Name des Alexa/Amazon Gerätetyps als String ausgeben setState(devicePfad + device +".Last_Status",res.statusCode.toString()+" " + statusCode(res.statusCode)); if(res.statusCode != 200) { log("Negative Rückmeldung von Alexa: " + res.statusCode + ": " + statusCode(res.statusCode),"warn"); log("Gesendetes Kommando: " + data,"warn"); } else { log('STATUS: ' + res.statusCode + ": " + statusCode(res.statusCode)); // Statuscode } if(logOn || res.statusCode != 200) log('HEADERS: ' + JSON.stringify(res.headers), (res.statusCode != 200 ? "warn" : "info")); // Header (Rückmeldung vom Webserver) }); req.on('error', function(e) { // Fehler abfangen log('ERROR: ' + e.message,"warn"); }); if(logOn) log("Data to request body: " + data); // write data to request body if(data) req.write(data); req.end();
}
function umlaut(str) {
return str
.replace(/ |À|Å|Ã/g, "A")
.replace(/â|à|å|ã/g, "a")
.replace(/Ä/g, "AE")
.replace(/ä/g, "ae")
.replace(/Ç/g, "C")
.replace(/ç/g, "c")
.replace(/É|Ê|È|Ë/g, "E")
.replace(/é|ê|è|ë/g, "e")
.replace(/Ó|Ô|Ò|Õ|Ø/g, "O")
.replace(/ó|ô|ò|õ/g, "o")
.replace(/Ö/g, "OE")
.replace(/ö/g, "oe")
.replace(/Š/g, "S")
.replace(/š/g, "s")
.replace(/ß/g, "ss")
.replace(/Ú|Û|Ù/g, "U")
.replace(/ú|û|ù/g, "u")
.replace(/Ü/g, "UE")
.replace(/ü/g, "ue")
.replace(/Ý|Ÿ/g, "Y")
.replace(/ý|ÿ/g, "y")
.replace(/Ž/g, "Z")
.replace(/ž/, "z");
}function statusCode(status) { // gibt zum http-Status eine Rückmeldung als String
if(status === 0) return "** Daten unvollständig ** (csrf fehlt/falsch? Cookie falsch?)";
if(status == 200) return "** OK ";
if(status == 302) return " Found (Moved Temporarily) ** (Cookie abgelaufen?)";
if(status == 401) return "** Unauthorized ** (Cookie nicht richtig gesetzt?)";
if(status == 403) return "** Forbidden ** (Kombination Cookie, deviceType, Seriennummer richtig?)";
if(status == 404) return "** Not Found ** (Kommando im Kontext des Geräts sinnvoll?)";
if(status == 500) return "** Internal Server Error** (ggf. Kommando im falschen Kontext verwendet?)";
return "Fehler";
}function deviceTypeStr(deviceType){ // Anhand der Amazon Device Kennung wird ein String mit dem Typ als Namen zurückgeliefert
if(!knownDeviceType[deviceType] || knownDeviceType[deviceType] === undefined) return "Gerät unbekannt";
return knownDeviceType[deviceType].device;
}function alexaCommand(device,cmd,parameter) { // Fürt ein Kommando (cmd) an ein Alexa-Gerät (device) mit optionalen Parameter (parameter) aus
var data;
if(!echos[device] || echos[device] === undefined) return log("Kein gültiger Raum","warn");
if(logOn) log("Kommando für: " + device);
switch (cmd) {case "volume": if(!parameter ||parameter === null){ log("Alexa Volume: keine Lautstärke angegeben. Parameter fehlt.","warn"); break; } parameter = parseInt(parameter); if(parameter < 0) { parameter = 0; log("Alexa Volume: ungültige Lautsträke angegeben (<0). Auf 0 gesetzt.","warn"); } if(parameter > 100) { parameter = 100; log("Alexa Volume: ungültige Lautsträke angegeben (>100). Auf 1000 gesetzt.","warn"); } httpsReqCmd(device,'{"type":"VolumeLevelCommand","volumeLevel":'+parameter+'}'); break; case "pause": httpsReqCmd(device,'{"type":"PauseCommand"}'); break; case "play": httpsReqCmd(device,'{"type":"PlayCommand"}'); break; case "next": httpsReqCmd(device,'{"type":"NextCommand"}'); break; case "previous": httpsReqCmd(device,'{"type":"PreviousCommand"}'); break; case "forward": httpsReqCmd('{"type":"ForwardCommand"}'); break; case "rewind": httpsReqCmd(device,'{"type":"RewindCommand"}'); break; case "shuffle": if(parameter === null){ log("Alexa Shuffle: kein true/false angegeben. Auf true gesetzt.","warn"); parameter = true; } httpsReqCmd(device,'{"type":"ShuffleCommand","shuffle":'+parameter+'}'); break; case "tunein": httpsReqCmd(device,'{"type":"tunein","station":"'+parameter+'"}'); break; default: log("Kein bekanntes Kommando angegeben: "+cmd,"warn"); break; }
}
// Subscriptions
// -----------------------------------------------------------------------------function setOn() {
var reg = new RegExp("^javascript\."+instance+"\." + devicePfad.replace('.', '\.') + ".*\.(volume|pause|play|next|forward|rewind|shuffle|tunein|radio|previous)");
on({"id":reg , "change": "any"}, function (obj) {
var objArr = obj.id.match(/(^.+).(.+).(.+)$/, ""); //Aufteilung in Pfad + Device + CMD
var device = objArr[2];
var cmd = objArr[3];
if(logOn) log("Device: " + device+", Kommando: " + cmd);switch (cmd) { case "radio": if(obj.state.val) { // default Radiostation einschalten setState(devicePfad + device +".tunein",defaultRadiostation); return; } else { // Musik auf Pause. setState(devicePfad + device +".pause",true); return; } break; // Buttons, true zum auslösen. Werden danach wieder auf flase gesetzt case "pause": case "play": case "next": case "forward": case "rewind": case "previous": if(getState(obj.id).val) setState(obj.id,false); // Button wieder auf false zurücksetzen, wenn er true war if(obj.state.val) alexaCommand(device,cmd,true); // Kommando war ein true -> Kommando ausführen break; // Switches oder Wert case "shuffle": case "volume": case "tunein": alexaCommand(device,cmd,obj.state.val); break; default: log("Kommando << "+cmd+" >> im Skript nicht behandelt","warn"); break; } }); log("--- Subscriptions angelegt ---");
}
onStop(function skriptStop () {
if (req) {
req.end();
}log("**** Skript wurde gestoppt ****");
}, 2000 /ms/);
// main
// -----------------------------------------------------------------------------
function main() {
//alexaCommand("arbeitszimmer","pause");
if (ok) {
log("--- Alexa Kommandos - Skript initalisiert und bereit ---");
} else {
log("--- Skript konnte nicht sauber initalisiert werden ---","warn");
}
}// Start Skript:
// -----------------------------------------------------------------------------log("--- Alexa Kommandos - Skript gestartet ---");
if(forecreation) log("Forcecreation ist eingeschaltet. Wenn nicht mehr benötigt, bitte im Skript auf false setzen","warn");
httpsReqGet('/api/devices/device',dpAbfrageAlexaAnlegen); // fragt bei Alexa die Devices ab und legt die Datenpunkte und dann die Subscriptions an
setTimeout(main, 7000); // startet main()`
Aber wie gesagt vor dem Update lief es[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i] -
ich habe nicht aktualisiert, aber in dem Thread glaube ich ähnliche Fehler gepostet. Wahrscheinlich habe ich das Skript erst implementiert, als ich schon einen aktuellen JS Adapter hatte.
host.iobrokerNUC 2018-01-20 10:36:10.397 error instance system.adapter.javascript.0 terminated with code 6 (uncaught exception) host.iobrokerNUC 2018-01-20 10:36:10.397 error Caught by controller[0]: at process._tickCallback (internal/process/next_tick.js:104:9) host.iobrokerNUC 2018-01-20 10:36:10.397 error Caught by controller[0]: at _combinedTickCallback (internal/process/next_tick.js:80:11) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at endReadableNT (_stream_readable.js:974:12) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at IncomingMessage.emit (events.js:185:7) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at emitNone (events.js:91:20) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at IncomingMessage. (script.js.common.Amazon.Alexa:212:81) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at dpAbfrageAlexaAnlegen (script.js.common.Amazon.Alexa:243:32) host.iobrokerNUC 2018-01-20 10:36:10.396 error Caught by controller[0]: at Object.parse (native) host.iobrokerNUC 2018-01-20 10:36:10.395 error Caught by controller[0]: SyntaxError: Unexpected end of JSON input javascript.0 2018-01-20 10:36:08.954 error SyntaxError: Unexpected end of JSON input at Object.parse (native) at dpAbfrageAlexaAnlegen (script.js.common.Amazon.Alexa:243:32) at IncomingMessage. (script.js.common.Amazon.A javascript.0 2018-01-20 10:36:08.954 error uncaught exception: Unexpected end of JSON input
-
Und was war hier jetzt die Lösung ?
-
In dem Fall war das JSON was jemand mit "JSON.parse" parsen wollte ungültig und wirf daher diese exception.
Wäre meine Vermutung.
Da fehlt Fehlerbehandlung
-
Hi…mein Problem das ich noch nicht genau weiß wie die Fehlermeldung und Script lesen soll !
Gibt es dazu eine Anleitung. Ständig Fragen nervt. :roll: Wie es ja auch lernen....
Hier mein Script dazu:
! // AlexaControl
! //
! // Version: v0.1.6
! // Author: Hauke
! // Dank an ruhr70 dessen Skript als Vorlage diente
! // http://forum.iobroker.net/viewtopic.php?f=37&t=6035
! // und Stefan.Franke, dessen Skript den Login per Cookie ermöglicht
! // http://forum.iobroker.net/viewtopic.php … gOn#p98493
! // Changelog:
! // v.0.1.6 Fehler behoben: Cannot use 'in' operator to search for 'provider' in undefined
! // v.0.1.5 Dummy-Objekte, falls Alexa {"message":null} antwortet, weil das Device derzeit nicht aktiv ist
! // v.0.1.4 Spielzeit und Titellänge werden nun im 2-Sekunden-Takt berechnet
! // v.0.1.3 WiFi ESSID / MAC werden ausgelesen
! // v.0.1.2 Playlists
! // v.0.1.1 History
! // v.0.1.0 erste brauchbare Version
! // ----------------------------------------------------------------------------------------------------
! // Settings:
! // ----------------------------------------------------------------------------------------------------
! // Loglevel kann folgenden Wert haben: debug, info, warn, error, none
! var logLevel = 'info';
! // true: Datenpunkte werden überschrieben (wenn z.B. Bezeichnungen geändert wurden)
! var forceCreation = true;
! // Pfad im Javascript-Adapter unter dem die Geräte angelegt werden sollen bei "Alexa" wird daraus z.B.: javascript.0.Alexa
! var pfad = "AlexaControl";
! // Hier die Datenpunkti mit dem Cookie und CSRF aus dem Script von Stefan.Franke
! var idCookie = "javascript.0.productive.alexalogon.cookie";
! var idCsrf = "javascript.0.productive.alexalogon.csrf";
! // Einslive - Default Radiostation für den Radio an Button.
! var defaultRadiostation = "s24885";
! // Jede Minute History auslesen? Wert im üblichen Unix Crontab-Stil
! // Manuell jeder Zeit per Button möglich.
! var updateHistoryScheduler = "* * * * ";
! // Wie oft Playlists automatisch auslesen? Wert im üblichen Unix Crontab-Stil
! // Manuell jeder Zeit per Button möglich.
! var updatePlaylistScheduler = "0 0 * * ";
! // Sollen Geräte gelistet werden, die nicht Kontrolliert werden können? (TV-Stick, etc.)
! // Hier wird dann nur die Gruppe "device" erstellt. "player" und "control" werden nicht erstellt.
! var listNonCotrollable = false;
! // Liste der bekannten Devicetypen, Geräte mit bekannten DeviceType
! // auf das ursprüngliche "anlegen" kann verzichtet werden, da die Capabilities geparst werden.
! // Nur Steuerbare Devices werden mit Steuer-Objekten versehen
! var knownDeviceType = {
! "A3S5BH2HU6VAYF": "Echo Dot 2.Gen",
! "AB72C64C86AW2": "Echo",
! "A7WXQPH584YP": "Echo 2.Gen",
! "A10A33FOX2NUBK": "Echo Spot",
! "A1NL4BVLQ4L3N3": "Echo Show",
! "A15ERDAKK5HQQG": "Sonos",
! "A2E0SNTXJVT7WK": "Fire TV V1",
! "ADVBD696BHNV5": "Fire TV Stick V1",
! "A2LWARUGJLBYEW": "Fire TV Stick V2",
! "A2T0P32DY3F7VB": "echosim.io",
! "AILBSA2LNTOYL": "reverb App",
! "A2M35JJZWCQOMZ": "Echo Plus"
! };
! // ----------------------------------------------------------------------------------------------------
! // Skript, ab hier nichts ändern
! // ----------------------------------------------------------------------------------------------------
! // Initiale Variablen setzen
! // ------------------------------------------------------
! //Script von Stefan.Franke nötig, welches csrf und cookie ausliest
! var csrf = getState(idCsrf).val;
! var cookie = getState(idCookie).val;
! cookie = cookie.replace(/\/g, "");
! // Object-Pfad definieren unter dem Devices angelegt werden
! var deviceObjectPath = pfad + ".Devices.";
! // Node Module https verwenden
! var https = require('https');
! // CUSTOMERID wird später aus der Geräteliste ausgelesen
! var mediaOwnerCustomerId;
! // globales Objekt mit allen Devices
! var devices = {};
! // LoglevelInt defniniern und dann Wert aus den Settings setzen
! var logLevelInt = 5;
! setLoglevel(logLevel);
! // Beim Programmende eine Info ausgeben
! onStop(function skriptStop () {
! logInfo("** AlexaControl wurde gestoppt ");
! }, 2000 /ms/);
! // Das eigentliche Programm läuft ab hier
! // ------------------------------------------------------
! logInfo(" AlexaControl wurde gestartet ");
! if(forceCreation) {
! logWarn("Forcecreation ist eingeschaltet. Wenn nicht mehr benötigt, bitte im Skript auf false setzen");
! }
! // Objekte auslegen und anlegen
! initAlexa();
! // updates History
! schedule(updateHistoryScheduler, function () {rescanHistory();});
! // updates Playlists
! schedule(updatePlaylistScheduler, function () {updatePlaylists();});
! // -------------------------------------------------------------------------------------------------------
! // Objekte Auslesen
! // -------------------------------------------------------------------------------------------------------
! /
! * liest per https-GET die aktuellen Playlists von Amazon ein und speichert diese in die "Playlists.X" States
! /
! function updatePlaylists() {
! logInfo('[updatePlaylists]');
! // zur Abfrage wird der erste Echo mit MusicPlayer verwendet
! var echoWithMusicPlayer = getEchoWithMusicPlayerFromDevices();
! var path = '/api/cloudplayer/playlists?deviceSerialNumber=' + echoWithMusicPlayer.serialNumber + '&deviceType=' + echoWithMusicPlayer.deviceType + '&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
! httpsReqGet(
! path,
! function (result) {
! tmpListe = JSON.parse(result).playlists;
! var playlistsJSON = [];
! var playlistsTitles = [];
! var playlistsIDs = [];
! for (playlist in tmpListe) {
! var obj = {
! "title": tmpListe[playlist][0].title,
! "playlistId": tmpListe[playlist][0].playlistId
! };
! playlistsJSON.push(obj);
! playlistsTitles.push(tmpListe[playlist][0].title);
! playlistsIDs.push(tmpListe[playlist][0].playlistId);
! }
! setState(pfad + ".Playlists.JSON", JSON.stringify(playlistsJSON));
! setState(pfad + ".Playlists.Titles", playlistsTitles.join(';'));
! setState(pfad + ".Playlists.IDs", playlistsIDs.join(';'));
! }
! );
! }
! /
! * liest per https-GET die letzten 20 Alexa-History-Einträge von Amazon ein und speichert diese in die "Playlists.X" States
! /
! function rescanHistory() {
! logInfo('[rescanHistory]');
! var path = 'https://alexa.amazon.de/api/activities? … 0&offset=1';
! httpsReqGet(
! path,
! function (result) {
! activities = JSON.parse(result).activities;
! creationTime = getState(pfad + ".History.creationTime").val;
! for(var i = (activities.length - 1); i > 0; i--) {
! if ((activities__.creationTimestamp > creationTime) || creationTime === null) {
! deviceName = getDeviceNameBySerialNumber(activities__.sourceDeviceIds[0].serialNumber);
! setState(pfad + ".History.creationTime", activities__.creationTimestamp);
! setState(pfad + ".History.deviceName", deviceName);
! setState(pfad + ".History.summary", JSON.parse(activities__.description).summary);
! }
! }
! }
! );
! }
! /
! * Updated ein Device per DatenpunktName, sowohl "control", als auch "player" wird
! * abgerufen und gespeichert befindet sich currentState im Modus "PLAYING", so wird
! * mit einem Timeout diese Funktion für das Device erneut aufgerufen
! *
! * @param string deviceDpName
! /
! function updateDevice(deviceDpName){
! if(typeof(devices[deviceDpName]) != "undefined") {
! if (deviceIsControllable(devices[deviceDpName].capabilities)) {
! logInfo('[updateDevice] ' + deviceDpName);
! var controlPath = deviceObjectPath + clearName(deviceDpName) + ".control";
! // deviceObjectPath + clearName(deviceDpName) + ".control.lastState"
! getDeviceStateBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, function(deviceState){
! // nur updaten, wenn unterschiedlich
! if (deviceState.volume != getState(controlPath + ".volume").val) {
! setState(controlPath + ".volume", parseInt(deviceState.volume));
! }
! if(deviceHasMusicPlayer(devices[deviceDpName].capabilities)){
! if (deviceState.shuffling != getState(controlPath + ".shuffle").val) {
! setState(controlPath + ".shuffle", deviceState.shuffling);
! }
! if (deviceState.looping != getState(controlPath + ".repeat").val) {
! setState(controlPath + ".repeat", deviceState.looping);
! }
! }
! getDevicePlayerBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, function(devicePlayer){
! // player
! var playerPath = deviceObjectPath + clearName(deviceDpName) + ".player";
! setState(playerPath + ".contentType", getStringOrEmpty(deviceState.contentType));
! setState(playerPath + ".currentState", getStringOrEmpty(deviceState.currentState));
! setState(playerPath + ".imageURL", getStringOrEmpty(deviceState.imageURL));
! setState(playerPath + ".muted", deviceState.muted);
! setState(playerPath + ".providerId", getStringOrEmpty(deviceState.providerId));
! setState(playerPath + ".radioStationId", getStringOrEmpty(deviceState.radioStationId));
! setState(playerPath + ".service", getStringOrEmpty(deviceState.service));
! var providerName = '';
! if ((devicePlayer !== undefined) && ("provider" in devicePlayer) && (devicePlayer.provider !== null)){
! providerName = getStringOrEmpty(devicePlayer.provider.providerName);
! }
! setState(playerPath + ".providerName", providerName);
! var title = '';
! var interpreter = '';
! var album = '';
! if ((devicePlayer !== undefined) &&("infoText" in devicePlayer) && (devicePlayer.infoText !== null)){
! title = getStringOrEmpty(devicePlayer.infoText.title);
! interpreter = getStringOrEmpty(devicePlayer.infoText.subText1);
! album = getStringOrEmpty(devicePlayer.infoText.subText2);
! }
! setState(playerPath + ".title", title);
! setState(playerPath + ".interpreter", interpreter);
! setState(playerPath + ".album", album);
! var mainArtUrl = '';
! if ((devicePlayer !== undefined) &&("mainArt" in devicePlayer) && (devicePlayer.mainArt !== null)){
! mainArtUrl = getStringOrEmpty(devicePlayer.mainArt.url);
! }
! setState(playerPath + ".mainArtUrl", mainArtUrl);
! var miniArtUrl = '';
! if ((devicePlayer !== undefined) &&("miniArt" in devicePlayer) && (devicePlayer.miniArt !== null)){
! miniArtUrl = getStringOrEmpty(devicePlayer.miniArt.url);
! }
! setState(playerPath + ".miniArtUrl", miniArtUrl);
! var mediaLength = 0;
! var mediaProgress = 0;
! var mediaProgressPercent = 0;
! if ((devicePlayer !== undefined) &&("progress" in devicePlayer) && (devicePlayer.progress !== null)){
! mediaLength = parseInt(devicePlayer.progress.mediaLength);
! mediaProgress = parseInt(devicePlayer.progress.mediaProgress);
! if (mediaLength > 0) {
! mediaProgressPercent = Math.round(((mediaProgress * 100) / mediaLength));
! }
! }
! setState(playerPath + ".mediaLength", mediaLength);
! setState(playerPath + ".mediaLengthStr", sekToHMS(mediaLength));
! setState(playerPath + ".mediaProgress", mediaProgress);
! setState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgress));
! setState(playerPath + ".mediaProgressPercent", mediaProgressPercent);
! });
! });
! } else {
! logInfo('[updateDevice] Device not controllable: ' + deviceDpName);
! }
! }else {
! logInfo('[updateDevice] Device unknown: ' + deviceDpName);
! }
! }
! /*
! * Inkrementiert "mediaProgress" alle 2 Sekunden um 2. So wird ein permanentes https-get überflüssig
! * ruft sich nach 2 Sekunden erneut selbst auf, wenn "currentState" noch auf "PLAYING" steht.
! * ist "mediaProgress" größer als "mediaLength", so ist der Song zu Ende und "updateDevice" wird aufgerufen.
! *
! * @param string deviceDpName
! /
! function updateMediaProgress(deviceDpName) {
! var playerPath = deviceObjectPath + deviceDpName + ".player";
! var currentState = getState(playerPath + ".currentState").val;
! var mediaProgress = getState(playerPath + ".mediaProgress").val;
! var mediaLength = getState(playerPath + ".mediaLength").val;
! if ((currentState == 'PLAYING') ) {
! mediaProgressNew = mediaProgress + 2;
! // Am Ende des Titels soll neu geladen werden. Ist es Radio (länge = 0) dann alle 200 sekunden
! if ((mediaProgressNew > mediaLength) && ((mediaLength > 0) || (mediaProgressNew % 200 < 2))){
! setTimeout( function() { updateDevice(deviceDpName); }, 2000 );
! }
! // Nun mediaProgress und mediaProgressPercent neu berechnen
! if (mediaLength > 0) {
! mediaProgressPercent = Math.round((((mediaProgressNew) * 100) / mediaLength));
! } else {
! mediaProgressPercent = 0;
! }
! setState(playerPath + ".mediaProgressPercent", mediaProgressPercent);
! setState(playerPath + ".mediaProgress", mediaProgressNew);
! setState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgressNew));
! setTimeout( function() { updateMediaProgress(deviceDpName); }, 2000 );
! }
! }
! /*
! * Ruft den aktuellen State eines Devices per Seriennummer und Type von Amazon ab.
! * Gibt die Antwort an "callback(result)" weiter
! *
! * @param string serialNumber
! * @param string deviceType
! * @param function callback
! /
! function getDeviceStateBySerialAndType(serialNumber, deviceType, callback) {
! httpsReqGet(
! '/api/media/state?deviceSerialNumber=' + serialNumber + '&deviceType=' + deviceType,
! function(result) {
! // Es kommt vor, dass Geräte nicht antworten, weil sie nicht aktiv sind. Dann greift hier der Dummy-Wert
! if (result == '{"message":null}') {
! result = JSON.stringify({
! "clientId":null,
! "contentId":null,
! "contentType":null,
! "currentState":"IDLE",
! "imageURL":null,
! "isDisliked":false,
! "isLiked":false,
! "looping":false,
! "mediaOwnerCustomerId":null,
! "muted":false,
! "programId":null,
! "progressSeconds":0,
! "providerId":null,
! "queue":null,
! "queueId":null,
! "queueSize":0,
! "radioStationId":null,
! "radioVariety":0,
! "referenceId":null,
! "service":null,
! "shuffling":false,
! "timeLastShuffled":0,
! "volume":0
! });
! }
! if(callback !== undefined && typeof callback === 'function') callback(JSON.parse(result));
! }
! );
! }
! /*
! * Ruft den aktuellen State eines Devices per DatenpunktNamen von Amazon ab.
! * Gibt die Antwort an "callback(result)" weiter
! *
! * @param string deviceDpName
! * @param function callback
! /
! function getDeviceState(deviceDpName, callback) {
! getDeviceStateBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, callback);
! }
! /*
! * Ruft die aktuelle PlayerInfo eines Devices per Seriennummer und Type von Amazon ab.
! * Gibt die Antwort an "callback(result)" weiter
! *
! * @param string serialNumber
! * @param string deviceType
! * @param function callback
! /
! function getDevicePlayerBySerialAndType(serialNumber, deviceType, callback) {
! httpsReqGet(
! '/api/np/player?deviceSerialNumber=' + serialNumber + '&deviceType=' + deviceType,
! function(result) {
! // Es kommt vor, dass Geräte nicht antworten, weil sie nicht aktiv sind. Dann greift hier der Dummy-Wert
! if (result == '{"message":null}') {
! result = JSON.stringify({
! "playerInfo":{
! "hint":null,
! "infoText":null,
! "isPlayingInLemur":false,
! "lemurVolume":null,
! "lyrics":null,
! "mainArt":null,
! "mediaId":null,
! "miniArt":null,
! "miniInfoText":null,
! "playbackSource":null,
! "playingInLemurId":null,
! "progress":null,
! "provider":null,
! "queueId":null,
! "state":null,
! "template":null,
! "transport":null,
! "volume":null
! }
! });
! }
! if(callback !== undefined && typeof callback === 'function') callback(JSON.parse(result).playerInfo);
! }
! );
! }
! /*
! * Ruft die aktuelle PlayerInfo eines Devices per DatenpunktNamen von Amazon ab.
! * Gibt die Antwort an "callback(result)" weiter
! *
! * @param string deviceDpName
! * @param function callback
! /
! function getDevicePlayer(deviceDpName, callback) {
! getDevicePlayerBySerialAndType(devices[deviceDpName].serialNumber, devices[deviceDpName].deviceType, callback);
! }
! /*
! * liest per https-GET alle Alexa-fähigen Geräte neu ein und updated bei allen
! * bereits bekannten Geräten die Infos, wie z.B. Onlinestatus, WLAN, etc.
! /
! function updateAlexa(){
! logInfo('[updateAlexa]');
! httpsReqGet('/api/devices/device', function(result) {
! // Falls Result leer ist, soll nichts weiter gemacht werden
! if(!result) return logWarn("Es konnten keine Daten ermittelt werden! Cookie richtig?");
! logDebug(result);
! var alexaDeviceObj = JSON.parse(result);
! var numberOfDevices = alexaDeviceObj.devices.length;
! logInfo("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices);
! if (numberOfDevices < 1) {
! return logWarn("Error: Skript konnte keine Geräte abfragen");
! }
! // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben
! mediaOwnerCustomerId = getStringOrEmpty(alexaDeviceObj.devices[0].deviceOwnerCustomerId);
! // Devices
! for(var i = 0; i < numberOfDevices; i++) {
! // Nur bekannte Geraete updaten
! if(typeof(devices[clearName(alexaDeviceObj.devices_[i].accountName)]) != "undefined") {
! // Pruefen, ob das Geraet noch das selbe ist
! if (devices[clearName(alexaDeviceObj.devices_[i].accountName)].serialNumber != alexaDeviceObj.devices__.serialNumber){
! logError('Das Geraet "' + clearName(alexaDeviceObj.devices__.accountName) + '" hat nach update eine andere Seriennummer!');
! } else {
! var devicePath = deviceObjectPath + clearName(alexaDeviceObj.devices__.accountName) + ".device";
! httpsReqGet(
! '/api/device-wifi-details?deviceSerialNumber=' + alexaDeviceObj.devices__.serialNumber + '&deviceType=' + alexaDeviceObj.devices_.deviceType,
! function(result) {
! setState(devicePath + ".essid", getStringOrEmpty(JSON.parse(result).essid));
! setState(devicePath + ".macAddress", getStringOrEmpty(JSON.parse(result).macAddress));
! }
! );
! setState(devicePath + ".language", getStringOrEmpty(alexaDeviceObj.devices_.language));
! setState(devicePath + ".online", alexaDeviceObj.devices_.online);
! setState(devicePath + ".parentClusters", getStringOrEmpty(alexaDeviceObj.devices_.parentClusters));
! setState(devicePath + ".softwareVersion", getStringOrEmpty(alexaDeviceObj.devices_.softwareVersion));
! // Device updaten
! updateDevice(clearName(alexaDeviceObj.devices_.accountName));
! }
! }
! }
! });
! }
! // –-----------------------------------------------------------------------------------------------------
! // Objekte Anlegen
! // -------------------------------------------------------------------------------------------------------
! /*
! * liest per https-GET alle Alexa-fähigen Geräte ein und legt die Objekte an
! /
! function initAlexa() {
! httpsReqGet('/api/devices/device', function(result) {
! // Falls Result leer ist, soll nichts weiter gemacht werden
! if(!result) return logWarn("Es konnten keine Daten ermittelt werden! Cookie richtig?");
! logDebug(result);
! var alexaDeviceObj = JSON.parse(result);
! var numberOfDevices = alexaDeviceObj.devices.length;
! logInfo("Anzahl vorhandener Geräte mit Alexa Unterstützung: " + numberOfDevices);
! if (numberOfDevices < 1) {
! return logWarn("Error: Skript konnte keine Geräte abfragen");
! }
! // Kundenindiviuelle Customer ID aus dem ersten Gerät entnehmen -> in vorbereitete globale Variable schreiben
! mediaOwnerCustomerId = alexaDeviceObj.devices[0].deviceOwnerCustomerId;
! createDeviceState(pfad + ".mediaOwnerCustomerId", mediaOwnerCustomerId, forceCreation, {name:"Individuelle Kunden ID", type:"string", role:"value"});
! // Devices
! for(var i = 0; i < numberOfDevices; i++) {
! if (listNonCotrollable || deviceIsControllable(alexaDeviceObj.devices_.capabilities)) {
! devices[clearName(alexaDeviceObj.devices[i].accountName)] = createDevice(alexaDeviceObj.devices_, forceCreation);
! }
! }
! // Update
! createState(
! pfad + ".update",
! false,
! forceCreation,
! {name:"Update Devices", type:"boolean", role:"button"},
! null,
! function () {
! setTimeout(
! function() {
! logInfo("CreateON: " + pfad + ".update");
! on({id: "javascript." + instance + "." + pfad + ".update", change: "any"},
! function (obj){
! unsetButtonFirst(obj, function (obj) {updateAlexa();});
! })
! }
! ,
! 3000
! );
! }
! );
! // Playlists
! createDeviceState(pfad + ".Playlists.JSON", null, forceCreation, {name:"Playlists als JSON", type:"string", role:"state"});
! createDeviceState(pfad + ".Playlists.Titles", null, forceCreation, {name:"Playlist Titel als Liste fuer Dropdown", type:"string", role:"state"});
! createDeviceState(pfad + ".Playlists.IDs", null, forceCreation, {name:"Playlist IDs als Liste fuer Dropdown", type:"string", role:"state"});
! createState(
! pfad + ".Playlists.update",
! false,
! forceCreation,
! {name:"Update Playlists", type:"boolean", role:"button"},
! null,
! function () {
! setTimeout(
! function() {
! logInfo("CreateON: " + pfad + ".Playlists.update");
! on({id: "javascript." + instance + "." + pfad + ".Playlists.update", change: "any"},
! function (obj){
! unsetButtonFirst(obj, function (obj) {updatePlaylists();});
! })
! }
! ,
! 3000
! );
! }
! );
! // Einmalig die Playlists abfragen
! updatePlaylists();
! // History
! createState(pfad + ".History.creationTime", null, forceCreation, {name:"Timestamp", type:"number", role:"state"});
! createState(pfad + ".History.deviceName", null, forceCreation, {name:"deviceName", type:"string", role:"state"});
! createState(pfad + ".History.summary", null, forceCreation, {name:"summary", type:"string", role:"state"});
! createState(
! pfad + ".History.update",
! false,
! forceCreation,
! {name:"Update History", type:"boolean", role:"button"},
! null,
! function () {
! setTimeout(
! function() {
! logInfo("CreateON: " + pfad + ".History.update");
! on({id: "javascript." + instance + "." + pfad + ".History.update", change: "any"},
! function (obj){
! unsetButtonFirst(obj, function (obj) {rescanHistory();});
! })
! }
! ,
! 3000
! );
! }
! );
! // Erstmalig die History abgragen
! rescanHistory();
! });
! }
! /*
! * Erzeugt alle States zu einem übergebenen Device-Objekt. Anhand der "capabilities"
! * des Devices, werden, ggf. "control" und "player" States erstellt.
! *
! * @param object amazonDeviceObject
! * @param boolean forceCreation
! /
! function createDevice(amazonDeviceObject, forceCreation) {
! logInfo('createDevice: '+ amazonDeviceObject.accountName);
! var devicePath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".device";
! // device
! createDeviceState(devicePath + ".accountName", getStringOrEmpty(amazonDeviceObject.accountName), forceCreation, {name:"Name", type:"string", role:"value"});
! createDeviceState(devicePath + ".capabilities", getStringOrEmpty(JSON.stringify(amazonDeviceObject.capabilities)), forceCreation, {name:"Fähigkeiten", type:"string", role:"value"});
! createDeviceState(devicePath + ".clusterMembers", getStringOrEmpty(JSON.stringify(amazonDeviceObject.clusterMembers)), forceCreation, {name:"GruppenMitglieder", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceAccountId", getStringOrEmpty(amazonDeviceObject.deviceAccountId), forceCreation, {name:"AccountId", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceFamily", getStringOrEmpty(amazonDeviceObject.deviceFamily), forceCreation, {name:"DeviceFamily", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceOwnerCustomerId", getStringOrEmpty(amazonDeviceObject.deviceOwnerCustomerId), forceCreation, {name:"deviceOwnerCustomerId", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceType", getStringOrEmpty(amazonDeviceObject.deviceType), forceCreation, {name:"deviceType", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceTypeString", getStringOrEmpty(deviceTypeStr(amazonDeviceObject.deviceType)), forceCreation, {name:"deviceType als String", type:"string", role:"value"});
! createDeviceState(devicePath + ".deviceTypeFriendlyName", getStringOrEmpty(amazonDeviceObject.deviceTypeFriendlyName), forceCreation, {name:"deviceTypeFriendlyName", type:"string", role:"value"});
! httpsReqGet(
! '/api/device-wifi-details?deviceSerialNumber=' + amazonDeviceObject.serialNumber + '&deviceType=' + amazonDeviceObject.deviceType,
! function(result) {
! createDeviceState(devicePath + ".essid", getStringOrEmpty(JSON.parse(result).essid), forceCreation, {name:"essid", type:"string", role:"value"});
! createDeviceState(devicePath + ".macAddress", getStringOrEmpty(JSON.parse(result).macAddress), forceCreation, {name:"macAddress", type:"string", role:"value"});
! }
! );
! createDeviceState(devicePath + ".language", getStringOrEmpty(amazonDeviceObject.language), forceCreation, {name:"language", type:"string", role:"value"});
! createDeviceState(devicePath + ".online", amazonDeviceObject.online, forceCreation, {name:"online (Klappt nur bei ECHOs)", type:"boolean", role:"value"});
! createDeviceState(devicePath + ".parentClusters", getStringOrEmpty(amazonDeviceObject.parentClusters), forceCreation, {name:"Mitglied in dieser Gruppe", type:"string", role:"value"});
! createDeviceState(devicePath + ".serialNumber", getStringOrEmpty(amazonDeviceObject.serialNumber), forceCreation, {name:"serialNumber", type:"string", role:"value"});
! createDeviceState(devicePath + ".softwareVersion", getStringOrEmpty(amazonDeviceObject.softwareVersion), forceCreation, {name:"softwareVersion", type:"string", role:"value"});
! if (deviceIsControllable(amazonDeviceObject.capabilities)) {
! createDeviceControl(amazonDeviceObject, forceCreation);
! }
! return {
! 'serialNumber' : amazonDeviceObject.serialNumber,
! 'deviceType' : amazonDeviceObject.deviceType,
! 'capabilities' : amazonDeviceObject.capabilities
! };
! }
! /*
! * Erzeugt alle "control" und "player" States zu einem übergebenen Device-Objekt.
! * Für Initial-Werte wird das Device bei Amazon zunächst abgefragt
! *
! * @param object amazonDeviceObject
! * @param boolean forceCreation
! /
! function createDeviceControl(amazonDeviceObject, forceCreation) {
! logInfo('createDeviceControl: '+ amazonDeviceObject.accountName);
! var controlPath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".control";
! // control
! createDeviceState(controlPath + ".LastStatus", 'INIT', forceCreation, {name:"Letzter Status", type:"string", role:"value"});
! createDeviceControlState(controlPath + ".updateDevice", false, forceCreation, {name:"Device abfragen", type:"boolean", role:"button"});
! // deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".control.lastState"
! getDeviceStateBySerialAndType(amazonDeviceObject.serialNumber, amazonDeviceObject.deviceType, function(deviceState){
! createDeviceControlState(controlPath + ".volume", parseInt(deviceState.volume), forceCreation, {name:"Volume in Prozent(0-100)", type:"number", role:"level.volume"});
! createDeviceControlState(controlPath + ".pause", false, forceCreation, {name:"Pause", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".play", false, forceCreation, {name:"Play", type:"boolean", role:"button"});
! if(deviceHasMusicPlayer(amazonDeviceObject.capabilities)){
! createDeviceControlState(controlPath + ".next", false, forceCreation, {name:"Next (nächster Titel)", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".previous", false, forceCreation, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".forward", false, forceCreation, {name:"Forward (Hörbuch 30 Sekunden vor)", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".rewind", false, forceCreation, {name:"Rewind (Hörbuch 30 Sekunden zurück)", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".previous", false, forceCreation, {name:"Previous (vorheriger Titel)", type:"boolean", role:"button"});
! createDeviceControlState(controlPath + ".shuffle", deviceState.shuffling, forceCreation, {name:"Shuffel an/aus", type:"boolean", role:"switch"});
! createDeviceControlState(controlPath + ".repeat", deviceState.looping, forceCreation, {name:"Repeat an/aus)", type:"boolean", role:"switch"});
! createDeviceControlState(controlPath + ".playlistId", false, forceCreation, {name:"spiele Playlist", type:"string", role:"control.value"});
! }
! if(deviceHasTuneIn(amazonDeviceObject.capabilities)){
! createDeviceControlState(controlPath + ".radio", false, forceCreation, {name:"Letzte Radiostation an/aus", type:"boolean", role:"switch"});
! createDeviceControlState(controlPath + ".tunein", defaultRadiostation, forceCreation, {name:"tunein Radiosenderkennung", type:"string", role:"control.value"});
! }
! getDevicePlayerBySerialAndType(amazonDeviceObject.serialNumber, amazonDeviceObject.deviceType, function(devicePlayer){
! // player
! var playerPath = deviceObjectPath + clearName(amazonDeviceObject.accountName) + ".player";
! createDeviceState(playerPath + ".contentType", getStringOrEmpty(deviceState.contentType), forceCreation, {name:"contentType", type:"string", role:"value"}); // "LIVE_STATION" | "TRACKS" | "CUSTOM_STATION"
! createDeviceControlState(playerPath + ".currentState", getStringOrEmpty(deviceState.currentState), forceCreation, {name:"currentState", type:"string", role:"value"}); // "PAUSED" | "PLAYING"
! createDeviceState(playerPath + ".imageURL", getStringOrEmpty(deviceState.imageURL), forceCreation, {name:"Grosses Bild", type:"string", role:"value"});
! createDeviceState(playerPath + ".muted", deviceState.muted, forceCreation, {name:"muted", type:"boolean", role:"value"});
! createDeviceState(playerPath + ".providerId", getStringOrEmpty(deviceState.providerId), forceCreation, {name:"providerId", type:"string", role:"value"}); // "TUNE_IN" | "CLOUD_PLAYER" | "ROBIN"
! createDeviceState(playerPath + ".radioStationId", getStringOrEmpty(deviceState.radioStationId), forceCreation, {name:"radioStationId", type:"string", role:"value"}); // "s24885" | null
! createDeviceState(playerPath + ".service", getStringOrEmpty(deviceState.service), forceCreation, {name:"service", type:"string", role:"value"}); // "TUNE_IN" | "CLOUD_PLAYER" | "PRIME_STATION"
! var providerName = null;
! if ((devicePlayer !== undefined) &&("provider" in devicePlayer) && (devicePlayer.provider !== null)){
! providerName = getStringOrEmpty(devicePlayer.provider.providerName);
! }
! createDeviceState(playerPath + ".providerName", providerName, forceCreation, {name:"active providerName", type:"string", role:"value"}); // "Amazon Music" | "TuneIn Live-Radio"
! var title = '';
! var interpreter = '';
! var album = '';
! if ((devicePlayer !== undefined) &&("infoText" in devicePlayer) && (devicePlayer.infoText !== null)){
! title = getStringOrEmpty(devicePlayer.infoText.title);
! interpreter = getStringOrEmpty(devicePlayer.infoText.subText1);
! album = getStringOrEmpty(devicePlayer.infoText.subText2);
! }
! createDeviceState(playerPath + ".title", title, forceCreation, {name:"active title", type:"string", role:"value"});
! createDeviceState(playerPath + ".interpreter", interpreter, forceCreation, {name:"active interpreter", type:"string", role:"value"});
! createDeviceState(playerPath + ".album", album, forceCreation, {name:"active album", type:"string", role:"value"});
! var mainArtUrl = '';
! if ((devicePlayer !== undefined) &&("mainArt" in devicePlayer) && (devicePlayer.mainArt !== null)){
! mainArtUrl = getStringOrEmpty(devicePlayer.mainArt.url);
! }
! createDeviceState(playerPath + ".mainArtUrl", mainArtUrl, forceCreation, {name:"active mainArtUrl", type:"string", role:"value"});
! var miniArtUrl = '';
! if ((devicePlayer !== undefined) &&("miniArt" in devicePlayer) && (devicePlayer.miniArt !== null)){
! miniArtUrl = getStringOrEmpty(devicePlayer.miniArt.url);
! }
! createDeviceState(playerPath + ".miniArtUrl", miniArtUrl, forceCreation, {name:"active miniArtUrl", type:"string", role:"value"});
! var mediaLength = 0;
! var mediaProgress = 0;
! var mediaProgressPercent = 0;
! if ((devicePlayer !== undefined) &&("progress" in devicePlayer) && (devicePlayer.progress !== null)) {
! mediaLength = parseInt(devicePlayer.progress.mediaLength);
! mediaProgress = parseInt(devicePlayer.progress.mediaProgress);
! if (mediaLength > 0) {
! mediaProgressPercent = Math.round(((mediaProgress * 100) / mediaLength));
! }
! }
! createDeviceState(playerPath + ".mediaLength", mediaLength, forceCreation, {name:"active mediaLength", type:"number", role:"value"});
! createDeviceState(playerPath + ".mediaLengthStr", sekToHMS(mediaLength), forceCreation, {name:"active mediaLength als (HH:)MM:SS", type:"string", role:"value"});
! createDeviceState(playerPath + ".mediaProgress", mediaProgress, forceCreation, {name:"active mediaProgress", type:"number", role:"value"});
! createDeviceState(playerPath + ".mediaProgressStr", sekToHMS(mediaProgress), forceCreation, {name:"active mediaProgress als (HH:)MM:SS", type:"string", role:"value"});
! createDeviceState(playerPath + ".mediaProgressPercent", mediaProgressPercent, forceCreation, {name:"active mediaProgressPercent", type:"number", role:"value"});
! });
! });
! }
! /*
! * Erzeugt einen State und macht danach einen Logeintrag
! *
! * @param string objectdevicePath
! * @param mixed initialValue
! * @param boolean forceCreation
! * @param object common
! /
! function createDeviceState(objectdevicePath, initialValue, forceCreation, common) {
! createState(objectdevicePath, initialValue, forceCreation, common, null, function(){logInfo('createState: ' + objectdevicePath)});
! }
! /*
! * Erzeugt einen State und macht danach einen Logeintrag
! * Dann wird für den State eine "on()-Funktion" erzeugt, die die gewünschte Funktion ausfürht
! *
! * @param string objectdevicePath
! * @param mixed initialValue
! * @param boolean forceCreation
! * @param object common
! /
! function createDeviceControlState(objectdevicePath, initialValue, forceCreation, common) {
! createState(
! objectdevicePath,
! initialValue,
! forceCreation,
! common,
! null,
! function () {
! logInfo('createState: ' + objectdevicePath);
! setTimeout(
! function() {
! logInfo("CreateON: " + objectdevicePath);
! on({id: "javascript." + instance + "." + objectdevicePath, change: "any"},
! function (obj){
! var objArr = obj.id.match(/(^.+).(.+).(.+).(.+)$/, ""); //Aufteilung in devicePath + deviceDpName + CMD
! var deviceDpName = objArr[2];
! var cmd = objArr[4];
! logDebug("Device: " + deviceDpName+", Kommando: " + cmd);
! parameter = obj.state.val;
! var reloadCallback = function() {setTimeout(function() {updateDevice(deviceDpName);}, 3000);};
! switch (cmd) {
! // Buttons, werden immer wieder auf false gesetzt
! case "updateDevice":
! unsetButtonFirst(obj, function (obj) {updateDevice(deviceDpName);});
! break;
! case "pause":
! unsetButtonFirst(obj, function (obj) {setPause(deviceDpName, reloadCallback);});
! break;
! case "play":
! unsetButtonFirst(obj, function (obj) {setPlay(deviceDpName, reloadCallback);});
! break;
! case "next":
! unsetButtonFirst(obj, function (obj) {setNext(deviceDpName, reloadCallback);});
! break;
! case "previous":
! unsetButtonFirst(obj, function (obj) {setPrevious(deviceDpName, reloadCallback);});
! break;
! case "forward":
! unsetButtonFirst(obj, function (obj) {setForward(deviceDpName, reloadCallback);});
! break;
! case "rewind":
! unsetButtonFirst(obj, function (obj) {setRewind(deviceDpName, reloadCallback);});
! break;
! //Switch
! case "shuffle":
! if(parameter === null){
! logWarn("Alexa Shuffle: kein true/false angegeben. Auf true gesetzt.");
! parameter = true;
! }
! setShuffle(deviceDpName, parameter);
! break;
! case "repeat":
! if(parameter === null){
! logWarn("Alexa Repeat: kein true/false angegeben. Auf true gesetzt.");
! parameter = true;
! }
! setRepeat(deviceDpName, parameter);
! break;
! case "radio":
! if(obj.state.val) {
! // Letzte Radiostation einschlaten
! var stationId = getState(deviceObjectPath + deviceDpName + ".control.tunein").val;
! setTuneIn(deviceDpName,stationId, reloadCallback);
! } else {
! // Musik auf Pause.
! setPause(deviceDpName, reloadCallback);
! }
! break;
! case "volume":
! if(!parameter ||parameter === null){
! logWarn("Alexa Volume: keine Lautstärke angegeben. Parameter fehlt.");
! break;
! }
! parameter = parseInt(parameter);
! if(parameter < 0) {
! parameter = 0;
! logWarn("Alexa Volume: ungültige Lautsträke angegeben (<0). Auf 0 gesetzt.");
! }
! if(parameter > 100) {
! parameter = 100;
! logWarn("Alexa Volume: ungültige Lautsträke angegeben (>100). Auf 100 gesetzt.");
! }
! setVolume(deviceDpName, parameter);
! break;
! case "playlistId":
! setPlaylistId(deviceDpName, parameter, reloadCallback);
! break;
! case "tunein":
! setTuneIn(deviceDpName,parameter, reloadCallback);
! break;
! case "currentState":
! // den aktuellen "mediaProgress" berechnen, statt ihn immer neu runterzuladen
! if ((obj.oldState.val == 'PAUSED') && (obj.state.val == 'PLAYING')) {
! // Wechsel von Pause zu Playing
! updateMediaProgress(deviceDpName);
! } else if (obj.state.val == 'PLAYING') {
! // war vorher nicht Pause, nun aber Playing, dann überprüfen, ob sich "mediaProgress"
! // innerhalb einer gewissen Zeit verändert (dann wurde die Funktion bereits ausgeführt)
! var playerPath = deviceObjectPath + deviceDpName + ".player";
! setTimeout( function() {
! var mediaProgress = getState(playerPath + ".mediaProgress").val;
! setTimeout( function() {
! var mediaProgressNew = getState(playerPath + ".mediaProgress").val;
! // Wurde mediaProgress in der Zeit trotz PLAYING nicht verändert, dann trotzdem ausführen
! if (mediaProgressNew == mediaProgress){
! setState(playerPath + ".mediaProgress", mediaProgressNew + 7);
! updateMediaProgress(deviceDpName);
! }
! }, 5000 );
! }, 3000 );
! }
! break;
! default:
! logWarn("Kommando << "+cmd+" >> im Skript nicht behandelt");
! break;
! }
! })
! }
! ,
! 3000
! );
! }
! );
! }
! // –-----------------------------------------------------------------------------------------------------
! // HTTPS-GET/POST-Funktionen
! // -------------------------------------------------------------------------------------------------------
! /*
! * Setzt die Options für den https Request
! *
! * @param string path
! * @param string method - Should be GET oder POST
! /
! function setOptions(path,method) {
! var options = {
! "host": 'layla.amazon.de',
! "path": path,
! "method": method,
! "timeout":10000,
! "headers": {
! 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
! 'Content-Type': 'text/plain',
! 'csrf' : csrf,
! 'Cookie' : cookie
! }
! };
! return options;
! }
! /*
! * Erzeugt eine GET Anfrage
! * @param string path
! * @param function callback
! /
! function httpsReqGet(path,callback) {
! logDebug("Abfrage " + path + " an Alexa gesendet");
! var options = setOptions(path,"GET");
! var req = https.get(options, function getDevices(res) {
! logDebug('STATUS: ' + res.statusCode) + ": " + statusCode(res.statusCode); // Statuscode
! logDebug('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
! // Buffer the body entirely for processing as a whole.
! var bodyChunks = [];
! var chunkLine = 0;
! res.on('data', function(chunk) {
! chunkLine = chunkLine + 1;
! // Hier können die einzelnen Zeilen verarbeitet werden...
! logDebug("Zeilennummer: " + chunkLine+ " ,Inhalt: " + chunk);
! bodyChunks.push(chunk);
! }).on('end', function() {
! logDebug("ARRAY mit den einzelnen Zeilen: " + bodyChunks);
! logDebug("ARRAY Länge: " + bodyChunks.length);
! var body = Buffer.concat(bodyChunks);
! // ...und/oder das Gesamtergebnis (body).
! if(!body) log("keine Daten erhalten","warn");
! logDebug('BODY: ' + body);
! if(callback !== undefined && typeof callback === 'function') return callback(body);
! });
! });
! req.on('error', function(e) { // Fehler abfangen
! log('ERROR: ' + e.message,"warn");
! log("keinen gültigen Callback gefunden","warn");
! ok = false;
! });
! req.end();
! }
! /*
! * Setzt das Device auf die Lautstärke
! *
! * @param string deviceDpName
! * @param integer volumeLevel
! * @param function callback
! /
! function setVolume(deviceDpName, volumeLevel, callback) {httpsPostCmd(deviceDpName, '{"type":"VolumeLevelCommand","volumeLevel":' + volumeLevel + '}' , callback);}
! /*
! * Setzt das Device auf PLAY
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setPlay(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PlayCommand"}', callback);}
! /*
! * Setzt das Device auf PAUSE
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setPause(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PauseCommand"}', callback);}
! /*
! * Setzt das Device auf NEXT
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setNext(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"NextCommand"}', callback);}
! /*
! * Setzt das Device auf PREVIOUS
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setPrevious(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"PreviousCommand"}', callback);}
! /*
! * Setzt das Device auf FORWARD
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setForward(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"ForwardCommand"}', callback);}
! /*
! * Setzt das Device auf REWIND
! *
! * @param string deviceDpName
! * @param function callback
! /
! function setRewind(deviceDpName, callback) {httpsPostCmd(deviceDpName, '{"type":"RewindCommand"}', callback);}
! /*
! * Setzt für das Device SHUFFLE auf den gewünschten zustand
! *
! * @param string deviceDpName
! * @param boolean state
! * @param function callback
! /
! function setShuffle(deviceDpName, state, callback) {httpsPostCmd(deviceDpName, '{"type":"ShuffleCommand","shuffle":' + state + '}', callback);}
! /*
! * Setzt für das Device REPEAT auf den gewünschten zustand
! *
! * @param string deviceDpName
! * @param boolean state
! * @param function callback
! /
! function setRepeat(deviceDpName, state, callback) {httpsPostCmd(deviceDpName, '{"type":"RepeatCommand","repeat":' + state + '}', callback);}
! /*
! * Schickt ein Kommando an Alexa
! *
! * @param string deviceDpName
! * @param string postData
! * @param function callback
! /
! function httpsPostCmd(deviceDpName, postData, callback) {
! logInfo("[httpsPostCmd] Device: " + deviceDpName + " - Kommando: " + postData);
! var path = '/api/np/command?'
! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
! + '&deviceType=' + devices[deviceDpName].deviceType ;
! httpsPost(deviceDpName, path, postData, callback);
! }
! /*
! * Startet auf dem Device den Radiosender
! *
! * @param string deviceDpName
! * @param string stationId
! * @param function callback
! /
! function setTuneIn(deviceDpName,stationId, callback) {
! logInfo("[setTuneIn] Device: " + deviceDpName + " - TuneIn-StationId: " + stationId);
! var path = '/api/tunein/queue-and-play?'
! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
! + '&deviceType=' + devices[deviceDpName].deviceType
! + '&guideId=' + stationId
! + '&contentType=station&callSign=&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
! httpsPost(deviceDpName, path, '', callback);
! }
! /*
! * Startet auf dem Device die Playlist
! *
! * @param string deviceDpName
! * @param string playlistId
! * @param function callback
! /
! function setPlaylistId(deviceDpName, playlistId, callback) {
! logInfo("[setPlaylistId] Device: " + deviceDpName + " - PlaylistId: " + playlistId);
! var path = '/api/cloudplayer/queue-and-play?'
! + 'deviceSerialNumber=' + devices[deviceDpName].serialNumber
! + '&deviceType=' + devices[deviceDpName].deviceType
! + '&shuffle=false'
! + '&contentType=station&callSign=&mediaOwnerCustomerId=' + mediaOwnerCustomerId;
! httpsPost(deviceDpName, path, '{"playlistId":"' + playlistId + '"}', callback);
! }
! /*
! * Erzeugt eine POST Anfrage und setzt den Status-Code
! * der Anfrage in das 'control.LastStatus' Feld
! *
! * @param string deviceDpName
! * @param string path
! * @param string postData
! * @param function callback
! /
! function httpsPost(deviceDpName, path, postData, callback) {
! logDebug("[httpsPost] Device: " + deviceDpName + " Path: " + path + " postData: " + postData);
! var options = setOptions(path,"POST");
! // request object
! var req = https.request(options, function (res) {
! var result = '';
! res.on('data', function (chunk) {
! result += chunk;
! });
! res.on('end', function () {
! logDebug(result);
! setState(deviceObjectPath + deviceDpName +".control.LastStatus",res.statusCode.toString()+" " + statusCode(res.statusCode));
! if(res.statusCode != 200) {
! logWarn("Negative Rückmeldung von Alexa: " + res.statusCode + ": " + statusCode(res.statusCode));
! logWarn("Gesendetes Kommando: " + postData);
! } else {
! logDebug('STATUS: ' + res.statusCode + ": " + statusCode(res.statusCode)); // Statuscode
! }
! if(res.statusCode != 200){
! logWarn('HEADERS: ' + JSON.stringify(res.headers)); // Header (Rückmeldung vom Webserver)
! }
! if(callback !== undefined && typeof callback === 'function') callback(result);
! });
! res.on('error', function (err) {
! logWarn('ERROR: ' + err.message);
! })
! });
! // req error
! req.on('error', function (err) {
! logWarn('ERROR: ' + err.message);
! });
! //send request witht the postData form
! req.write(postData);
! req.end();
! }
! // –-----------------------------------------------------------------------------------------------------
! // Hilfs-Funktionen
! // -------------------------------------------------------------------------------------------------------
! /*
! * Setzt das gewünschte Loglevel
! *
! * @param string level
! /
! function setLoglevel(level) {
! switch(level.toLowerCase()) {
! case 'debug':
! logLevelInt = 0;
! break;
! case 'info':
! logLevelInt = 1;
! break;
! case 'warn':
! logLevelInt = 2;
! break;
! case 'error':
! logLevelInt = 3;
! break;
! case 'none':
! logLevelInt = 4;
! break;
! default:
! logLevelInt = 2;
! break;
! }
! }
! /*
! * Logt eine DEBUG Message
! * (wird als info geloggt, da Debug nicht angezeigt wird)
! *
! * @param string msg
! /
! function logDebug(msg) {
! if (logLevelInt <= 0) {
! log(msg, "info");
! }
! }
! /*
! * Logt eine INFO Message
! *
! * @param string msg
! /
! function logInfo(msg) {
! if (logLevelInt <= 1) {
! log(msg, "info");
! }
! }
! /*
! * Logt eine WARN Message
! *
! * @param string msg
! /
! function logWarn(msg) {
! if (logLevelInt <= 2) {
! log(msg, "warn");
! }
! }
! /*
! * Logt eine ERROR Message
! *
! * @param string msg
! /
! function logError(msg) {
! if (logLevelInt <= 3) {
! log(msg, "error");
! }
! }
! /*
! * Durchsucht ein Array nach needle und
! * liefert bei Erfolg TRUE
! *
! * @param string needle
! * @param array haystack
! * @return boolean
! /
! function inArray(needle, haystack) {
! var length = haystack.length;
! for(var i = 0; i < length; i++) {
! if(haystack == needle) return true;
! }
! return false;
! }
! /*
! * Gibt zurück, ob die capabilities ein Steuern zulassen
! *
! * @param array capabilities
! * @return boolean
! /
! function deviceIsControllable(capabilities) {
! return (inArray('AUDIO_PLAYER', capabilities)
! || inArray('AMAZON_MUSIC', capabilities)
! || inArray('TUNE_IN', capabilities));
! }
! /*
! * Gibt zurück, ob die capabilities eine Audiowiedergabe zulassen
! *
! * @param array capabilities
! * @return boolean
! /
! function deviceHasMusicPlayer(capabilities) {
! return (inArray('AUDIO_PLAYER', capabilities)
! || inArray('AMAZON_MUSIC', capabilities));
! }
! /*
! * Gibt zurück, ob die capabilities TuneIn und somit Radio zulassen
! *
! * @param array capabilities
! * @return boolean
! /
! function deviceHasTuneIn(capabilities) {
! return (inArray('TUNE_IN', capabilities));
! }
! /*
! * Button wieder auf false zurücksetzen, wenn er true war, danach callback
! *
! * @param object obj
! * @param function callback
! /
! function unsetButtonFirst(obj, callback) {
! if(getState(obj.id).val) {
! setState(obj.id,false);
! if(callback !== undefined && typeof callback === 'function') callback(obj);
! }
! }
! /*
! * Liefert str als String zurück, '' anstelle von null, false, …
! *
! * @param mixed str
! * @return string
! /
! function getStringOrEmpty(str){
! return (String(str) !== 'undefined') ? String(str) : '';
! }
! /*
! * Liefert das Device anhand der seriennummer
! *
! * @param string serialNumber
! * @param object
! /
! function getDeviceNameBySerialNumber(serialNumber) {
! for (device in devices) {
! if (devices[device].serialNumber == serialNumber) {
! return device;
! }
! }
! return null;
! }
! /*
! * Liefert das erste Device das einen MusicPlayer hat,
! * oder null, wenn es keines gibt
! *
! * @return object|null
! /
! function getEchoWithMusicPlayerFromDevices() {
! for (device in devices) {
! if (deviceHasMusicPlayer(devices[device].capabilities)) {
! return devices[device];
! }
! }
! return null;
! }
! /*
! * Liefert einen bereinigten Namen um daraus einen State-Pfad zu erzeugen
! *
! * @param string name
! * @return string
! */
! function clearName(name){
! name = umlaut(name);
! name = name.replace(/\W/g,"");
! return name;
! }
! /**
! * Ersetzt Umlaufe/Sonderzeichen
! *
! * @param string str
! * @return string
! /
! function umlaut(str) {
! return str
! .replace(/Â|À|Å|Ã/g, "A")
! .replace(/â|à|å|ã/g, "a")
! .replace(/Ä/g, "AE")
! .replace(/ä/g, "ae")
! .replace(/Ç/g, "C")
! .replace(/ç/g, "c")
! .replace(/É|Ê|È|Ë/g, "E")
! .replace(/é|ê|è|ë/g, "e")
! .replace(/Ó|Ô|Ò|Õ|Ø/g, "O")
! .replace(/ó|ô|ò|õ/g, "o")
! .replace(/Ö/g, "OE")
! .replace(/ö/g, "oe")
! .replace(/Š/g, "S")
! .replace(/š/g, "s")
! .replace(/ß/g, "ss")
! .replace(/Ú|Û|Ù/g, "U")
! .replace(/ú|û|ù/g, "u")
! .replace(/Ü/g, "UE")
! .replace(/ü/g, "ue")
! .replace(/Ý|Ÿ/g, "Y")
! .replace(/ý|ÿ/g, "y")
! .replace(/Ž/g, "Z")
! .replace(/ž/, "z");
! }
! /*
! * Liefert einen String zum http-Status
! *
! * @param integer status
! * @return string
! /
! function statusCode(status) {
! if(status === 0) return "* Daten unvollständig ** (csrf fehlt/falsch? Cookie falsch?)";
! if(status == 200) return "** OK ";
! if(status == 302) return " Found (Moved Temporarily) ** (Cookie abgelaufen?)";
! if(status == 401) return "** Unauthorized ** (Cookie nicht richtig gesetzt?)";
! if(status == 403) return "** Forbidden ** (Kombination Cookie, deviceType, Seriennummer richtig?)";
! if(status == 404) return "** Not Found ** (Kommando im Kontext des Geräts sinnvoll?)";
! if(status == 500) return "** Internal Server Error** (ggf. Kommando im falschen Kontext verwendet?)";
! return "Fehler";
! }
! /**
! * Liefert einen String zum deviceType
! *
! * @param integer deviceType
! * @return string
! /
! function deviceTypeStr(deviceType){
! if(!knownDeviceType[deviceType] || knownDeviceType[deviceType] === undefined) return "Gerät unbekannt";
! return knownDeviceType[deviceType];
! }
! /*
! * Konvertiert eine Sekundenzahl in einen String im Format (HH:)MM:SS
! *
! * @param integer sek
! * @return string
! */
! function sekToHMS(sek) {
! if (sek === 0) {
! return '0';
! }
! var sec_num = parseInt(sek, 10);
! var hours = Math.floor(sec_num / 3600);
! var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
! var seconds = sec_num - (hours * 3600) - (minutes * 60);
! if (minutes < 10) {minutes = "0"+minutes;}
! if (seconds < 10) {seconds = "0"+seconds;}
! if (hours === 0) {
! return minutes+':'+seconds;
! }
! if (hours < 10) {hours = "0"+hours;}
! return hours+':'+minutes+':'+seconds;
! }___________________________ _____________z.Beispiel was bedeuten die Zahlen am Ende von dem Fehler. Ist die Zeile von der Error im Script auftritt ?y controller[0]: at IncomingMessage. <anonymous>(script.js.Alexa_Device_Command:214:81)
Caught 2018-06-12 20:38:20.461 error by controller[0]: at dpAbfrageAlexaAnlegen (script.js.Alexa_Device_Command:245:32)
Caught 2018-06-12 20:38:20.461 error by controller[0]: at Object.parse (native)
Caught 2018-06-12 20:38:20.461 error by controller[0]: SyntaxError: Unexpected end of JSON input</anonymous>_____________