Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Hauke

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    H
    • Profile
    • Following 0
    • Followers 0
    • Topics 1
    • Posts 9
    • Best 0
    • Groups 1

    Hauke

    @Hauke

    0
    Reputation
    11
    Profile views
    9
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    Hauke Follow
    Starter

    Latest posts made by Hauke

    • RE: Trådfri und Gira System 55

      Für mich war bei meinem Schalter folgendes ausschlaggebend:

      • Integration in die bestehende Schalterserie
      • Der Schalter muss ohne Zentrale direkt mit den bestehenden Leuchtmitteln per Zigbee kommunizieren. (falls WLAN/internet/ioBroker/... ausfällt)
      • Preiswert
      • Funktionen: An/Aus/Dimmen
      • Entweder mit Netzteil, oder keine fest verbauten Schalter/Blenden, die zum Batteriewechsel abgebaut werden müssen und währenddessen Leitungen offen liegen. Das muss dann auch meine Frau Tauschen können.
      • Er muss anstelle vorhandener Schalter vor der UP-Dose montiert (dazu muss aus Sicherheitsgründen die Dose noch irgendwie von vorne abgedeckt werden) und eigenständig ohne UP-Dose angebracht werden können.

      Gerade in Sachen Preis ist diese Lösung sehr gut, weil es den Dimmer bei IKEA für nur 6€ (oder mit E27 Leuchtmittel für 10€) gibt und dazu nur noch eine Gira-Blende und etwas Kunststoffkleber benötigt wird.

      posted in Praktische Anwendungen (Showcase)
      H
      Hauke
    • Trådfri und Gira System 55

      Nabend.
      Ich wollte euch mal kurz zeigen, dass die neuen kleinen Dimmer von Ikea Trådfri sich super in die Schalterserie Gira System 55 integrieren lassen.

      Vorteil ist, dass es ein leichtes ist, die Batterie zu wechseln, wenn sie mal leer ist.

      _20200107_225425.JPG
      _20200107_225500.JPG
      _20200107_225523.JPG
      _20200107_225541.JPG
      _20200107_225609.JPG
      _20200107_225629.JPG
      _20200107_225651.JPG
      _20200107_225708.JPG

      _20200107_230048.JPG
      _20200107_230107.JPG

      posted in Praktische Anwendungen (Showcase)
      H
      Hauke
    • RE: Alexa Anbindung ohne Cloud und Skill

      Das mit dem Verstärker war nur ein Beispiel.

      Das Phänomen tritt auch bei meiner Heizung auf:

      Ich habe ein Script für meine elektrische Zusatzheizung geschrieben, das beim Anschalten einen Counter runterzählt und dann die Heizung wieder ausschaltet. Der Counter wird per Defaultwert beim Anschalten auf 30 Minuten gesetzt. Stelle ich per Alexa den Counter der Heizung auf 50 (entspricht dann 50 Minuten) und stelle dann den Counter manuell auf einen anderen Wert (z.B. 60), wird beim einfachen Einschalten(also ohne Angabe einer Zahl) nach dem Einschalten erst die 60 eingestellt und plötzlich die 50 erneut von Alexa übertragen.

      posted in Cloud Dienste
      H
      Hauke
    • RE: Alexa Anbindung ohne Cloud und Skill

      Nabend,

      bei mir ist Node-Red nun auch seit gestern Abend im Einsatz und ich bin sehr zufrieden.

      Ein "Feature" welches ich gefunden habe ist, dass die Helligkeit/Lautstärke/etc. immer beim einschaltern mitgeschickt wird und dann den vorherigen (nicht per alexa) eingestellten Wert überschreibt.

      Beispiel:
      5582_noderedverstaerker.png

      Sage ich "alexa - Verstärker auf 50" stellt er die Lautstärke auch auch 50.

      Stelle ich dann die Lautstärke per App oder (old school) per Fernbedienung, oder gar direkt am Gerät auf einen anderen Wert und stelle den Verstärker irgendwann aus, ist der neue Wert noch eingestellt.

      Sage ich dann "alexa - verstärker an" wird die Lautstärke wieder auf 50 gestellt, weil alexa dann nicht nur an schaltet, sondern auch die Lautstärke erneut übermittelt.

      Das taucht auch bei folgender Einstellung auf:
      5582_noderedverstaerker2.png

      Mache ich da etwas falsch, oder soll das so?

      posted in Cloud Dienste
      H
      Hauke
    • RE: [SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

      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…

      posted in Cloud Dienste
      H
      Hauke
    • RE: [SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

      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

      posted in Cloud Dienste
      H
      Hauke
    • RE: [SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

      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]

      posted in Cloud Dienste
      H
      Hauke
    • RE: [SKRIPT] Alexa über ioBroker Steuern -> Kommandos an Alexa

      @ludino:

      Kann man irgendwie die einzelnen Playlist über Vis wähbar machen? `

      Klar geht das 😉

      Habe mir vor einiger Zeit die selbe Frage gestellt und herausgekommen ist ein komplett überarbeitetes Skript, welches bei mir seit einiger Zeit im Betrieb ist.

      Ich habe es "AlexaControl" getauft, da es genau das tun soll.

      Da hin und wieder mal ein Fehler kommt, hatte ich es noch nicht hier bereitgestellt, aber wer möchte, dar es gerne testen:

      ! ```
      `// AlexaControl
      //
      // Version: v0.1.5
      // 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.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 (("provider" in devicePlayer) && (devicePlayer.provider !== null)){
      					providerName = getStringOrEmpty(devicePlayer.provider.providerName);
      				}
      				setState(playerPath + ".providerName", providerName);
      

      ! var title = '';
      var interpreter = '';
      var album = '';
      if (("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 (("mainArt" in devicePlayer) && (devicePlayer.mainArt !== null)){
      mainArtUrl = getStringOrEmpty(devicePlayer.mainArt.url);
      }
      setState(playerPath + ".mainArtUrl", mainArtUrl);
      ! var miniArtUrl = '';
      if (("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 (("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 (("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 (("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 (("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 (("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 (("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;
      

      }`

      ! Das schaut dann bei mir im VIS so aus:
      5582_echoguiplaylist.png
      ! Sobald eine PLaylist ausgewählt wird, wird diese auf dem Gerät, der der Gruppe abgespielt.
      ! Wird ein RadioButton geklickt, so wird stattdessen das Radio gestartet.
      ! Es gibt aber eine Vielzahl an Funktionen, die ich noch gar nicht alle im VIS nutze.

      *   ~~[*]~~Auf das ursprüngliche "anlegen" kann verzichtet werden, da die Capabilities geparst werden.  Nur Steuerbare Devices werden mit Steuer- und Payer-Objekten versehen.
      *   ~~[*]~~Der Onlinestatus wird nun für die ECHOs dargestellt, da diese nicht Pingbar sind.
      *   ~~[*]~~Die History wird minütlich bei Amazon abgerufen, oder bei Bedarf per State(-Button). In Verbindung mit der History von ioBroker, kann man so immer sehen, was wann über welches Gerät an Alexa gesagt wurde.
      *   ~~[*]~~Playlists werden jede Stunde abgerufen, oder bei Bedarf per State(-Button)
      *   ~~[*]~~WLAN essid und MAC wird nun für jedes Gerät abgefragt
      *   ~~[*]~~Repeat und Shuffle sind steuerbar.
      *   ~~[*]~~Während ein Device etwas abspielt, wird die Zeit im Hintergrund vom skript berechnet, damit die Sekunden hochzählen (im 2-Sekunden Takt) und nach dem Song automatisch der Player autmoatisch neu von Amazon geladen wird, um neues Bild, Titel, Interpret, etc. zu laden
      *   ~~[*]~~Eine Prozentuale berechnung der Spielzeit wird auch laufend aktualisiert, damit ein fortschrittsbalken möglich ist.
      *   ~~[*]~~...
      >! Ich bin nicht jeden Tag zu Hause am PC, falls also Probleme auftauchen, gerne bescheid geben, aber nicht erwarten, dass ich diese zeitnah fixen kann - Benutzung also auf eigene Gefahr ;)[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]
      ```
      posted in Cloud Dienste
      H
      Hauke
    • RE: [Vorlage] Denon Skript

      Moinsen.

      Mein erster Beitrag hier im Forum. Vielleicht hilft es jemandem.

      Ich habe gerade einige Zeit damit verbracht das Script erfolglos mit meinem Denon AVR X2000 zu testen.

      -> Die IP meines Receivers habe ich auf 192.168.0.140 eingestellt.

      -> Webinterface funktioniert

      -> Telnet Funtioniert

      -> Skript unter javascript Common/Denon eingepflegt nund gestartet: Die Objekte werden angelegt, dabei werden Fehler zur IP geschmissen, die ignoriert werden dürfen

      Soweit alles OK

      Nun trage ich ins Objekt meine korrekte IP im Format 192.168.000.140 ein und es kommt:

      10:12:06.918 [error] javascript.0 script.js.common.Denon.DenonControl: ungültige IP Adresse

      Trage ich ins Objekt die IP im Format 192.168.0.140 ein kommt folgendes:

      10:13:02.203 [info] javascript.0 script.js.common.Denon.DenonControl: Connectig…

      10:13:02.215 [info] javascript.0 script.js.common.Denon.DenonControl: Verbunden mit Denon AVR !

      10:13:02.216 [info] javascript.0 script.js.common.Denon.DenonControl: Update Start

      10:13:02.314 [info] javascript.0 script.js.common.Denon.DenonControl: Anfrage: NSET1 ?

      10:13:02.377 [info] javascript.0 script.js.common.Denon.DenonControl: NSET1DHC OFF

      10:13:02.412 [info] javascript.0 script.js.common.Denon.DenonControl: NSET1IPA 192.168.000.140

      10:13:02.418 [info] javascript.0 script.js.common.Denon.DenonControl: Anfrage: NSFRN ?

      10:13:02.429 [info] javascript.0 script.js.common.Denon.DenonControl: Connection closed !

      10:13:02.430 [error] javascript.0 script.js.common.Denon.DenonControl: ungültige IP Adresse

      Die Verbindung klappt also zu 192.168.0.140.

      Die IP wird dann im Objekt auf 192.168.000.140 geändert, was zum Fehler "ungültige IP Adresse" führt.

      Ich habe dann Zeile 414 auskommentiert

                      //setState('javascript.0.Denon.System.IP_Adresse',val=IPstring,akt=true);
      

      und die IP Adresse im Objekt manuell wieder auf 192.168.0.140 geändert.

      Siehe da: schon läuft alles wie es soll!

      Aus reiner Neugier wüsste ich gerne folgendes:

      Gibt es einen Grund, weshalb die IP aus dem Denon wieder zurück ins Objekt geschrieben wird? Immerhin klappt ja die Verbindung zu dem Zeitpunkt bereits mit der vorher bekannten IP.

      Vielleicht übersehe ich ja irgendwas wichtiges, aber da es bei mir aktuell läuft bin ich sehr zufrieden und danke allen, die an diesem Skript mitgearbeitet haben!

      posted in Skripten / Logik
      H
      Hauke
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo