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

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

Community Forum

  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. [Vorlage] Denon HEOS Script

NEWS

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

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

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

[Vorlage] Denon HEOS Script

Geplant Angeheftet Gesperrt Verschoben JavaScript
javascripttemplate
357 Beiträge 48 Kommentatoren 76.6k Aufrufe 44 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • UhulaU Uhula

    @withstu Vielen Dank withstu. Ich habe die meisten Dinge davon übernommen, andere anders implementiert. Wenn du Interesse hast, kannst du die neuste Version testen. Hier die Liste der Änderungen:

    v2.0 13.03.2020
    • das Script überprüft nun, ob alle notwendigen states für Heos und HeosPlayer im ioBroker korrekt erzeugt wurden und gibt eine Warnung mit Script-Neustartaufforderung aus, wenn die states nicht vorhanden sind. Dieses ist notwendig, da das Anlegen von states asynchron erfolgt und einige ms dauern kann
    • (WICHTIG!) die states werden nicht mehr in der aktuellen Javascript-Instanz und auch nicht mehr unter der IP des Heos-Players gespeichert, sondern Javascript-Instanzunabhängig unter 0_userdata.0 und seiner Player-ID (pid), da diese sich nicht ändert. Die IP hingegen u.U. schon. Also statt "javascript.X.heos.192_168_2_43" nun als "0_userdata.0.heos.12345678". Wer bereits auf die alten Werte im VIS zugreift, muss dieses im VIS anpassen!
    • es wurden Befehle/states für die Gruppensteuerung der Heos-Player hinzugefügt. Beim Start werden die Gruppen ausgelesen und in den Player-states des Gruppenleiters (der erste genannte Player) gespeichert. Über dessen states kann die Gruppe gesteuert werden:
      • group_leader : Ist Gruppenleiter
      • group_member : Ist Gruppenmitglied
      • group_pid : Player pids in der Gruppe
      • group_volume : Lautstärke wenn Gruppen-Leiter
      • group_name : Name der Gruppe
      • group_mute : Gruppe gemutet?
    • alle 60 Sek wird überprüft, ob noch alle HEOS-Player erreichbar sind bzw. neue/reconnectete hinzugekommen sind. Neue/reconnectete werden der Liste der HEOS-Player hinzugefügt, fehlende werden gestoppt. Da hierzu das HEOS-Netzwerk gefragt wird (get_players Meldung), kann es bis zu 5 Min dauern bis Änderungen erkannt werden. Der neue HEOS-Player-State "connected" wird entsprechend gesetzt
    • jeder HEOS-Player hat einen neuen state "connected", dieser wird nach erfolgreichem Start auf true gesetzt, bei korrektem Beenden des Scripts auf false
    • diverse Filter/Korrekturen aus dem Forum übernommen, vielen dank an withstu

    Die Script-Datei: heos_new.js

    Eine Beispiel-view für die Gruppen: heos_new_groupview.json (nutzt das MDCSS v2, aber an den Widgets kann man auch so das Prinzip erkennen)

    W Offline
    W Offline
    withstu
    schrieb am zuletzt editiert von
    #99

    @Uhula Danke für die neue Version. Ich habe an der V2 noch 3 kleine Änderungen vorgenommen.

    • Im get_now_playing_media fehlt die album_id
    if (jdata.payload.hasOwnProperty('album'))
       this.setState("now_playing_media_album", jdata.payload.album);
    if (jdata.payload.hasOwnProperty('album_id'))
       this.setState("now_playing_media_album_id", jdata.payload.album_id);
    if (jdata.payload.hasOwnProperty('artist'))
       this.setState("now_playing_media_artist", jdata.payload.artist);
    
    • Die unfinishedResponses habe ich wieder hinzugefügt (siehe meine Änderungen), sonst werden bei mir die Presets nicht geholt, da nicht vollständige Pakete verworfen werden.
    init() {
        this.statePath = '0_userdata.0.heos.';
        this.players = [];
        this.getPlayersInterval = undefined;
        this.net_client = undefined;
        this.nodessdp_client = undefined;
    
        this.ip='';
        this.msgs = [];
        this.lastResponse = '';
        this.state = stateDISCONNECTED;
        this.unfinishedResponses = '';
        this.ssdpSearchTargetName = 'urn:schemas-denon-com:device:ACT-Denon:1';
    }
    [...]
    onData(data) {  try {
        data = data.toString();
        data=data.replace(/[\n\r]/g, '');    // Steuerzeichen "CR" entfernen   
        // es können auch mehrere Antworten vorhanden sein! {"heos": ... } {"heos": ... }
        // diese nun in einzelne Antworten zerlegen
        data = this.unfinishedResponses + data;
        this.unfinishedResponses = '';
        
        data=data.replace(/{"heos":/g, '|{"heos":');    
        var responses = data.split('|');
        responses.shift();
        for (var r=0; r<responses.length; r++ ) if(responses[r].trim().length > 0) {
            try {
                JSON.parse(responses[r]); // check ob korrektes JSON Array
                this.parseResponse(responses[r]);
            } catch(e) {
                this.logDebug('onData: invalid json (error: ' + e.message + '): ' + responses[r]);
                this.unfinishedResponses += responses[r];
            }
        }
        // wenn weitere Msg zum Senden vorhanden sind, die nächste senden
        if (this.msgs.length>0)
            this.sendNextMsg();
    } catch(err) { this.logError( 'onData: '+err.message ); } }
    
    • Das leere setInterval in startPlayer() habe ich entfernt:
        this.setInterval(() => {
            
        }, 10000);
    

    Bisher läuft das Skript ganz gut. Läuft allerdings in einen Fehler, wenn alle Player ausgestellt wurden (war beim alten Script auch schon so): Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed

    1 Antwort Letzte Antwort
    0
    • W Offline
      W Offline
      withstu
      schrieb am zuletzt editiert von
      #100

      @Uhula Irgendwie funktioniert der keep alive Mechanismus vom net socket nicht korrekt. Auch wenn ich das Device ausgeschaltet habe, wurde das Timeout Event nicht geworfen. Habe jetzt den HEOS Heartbeat zusätzlich implementiert. Sollte der Master mal ausgeschaltet werden und der Heartbeat Timeout 60 Sekunden keine Reaktion von dem Device bekommen, wird nun ein reconnect bzw. eine Suche nach einem neuen Master durchgeführt. Zusätzlich wird die ssdp Suche jetzt so oft wiederholt, bis ein Device gefunden wurde.

      /****************************
      ### HEOS Script for ioBroker
      
      #### Funktion
      
      Das Script stellt zwei JS Klassen zur Steuerung der Denon HEOS Geräte zur Verfügung. Die class Heos dient dabei dem Erkennen und Steuern der HEOS Geräte. Die class HeosPlayer dient der Interpretation der Antworten der Heos Geräte.
       
      Das Script muss lediglich gestartet werden, es sucht dann im Netzwerk nach HEOS Playern und erzeugt in der aktuellen Javascript-Instanz einen Subeintrag für die Favoriten und je einen Subeintrag für jeden gefundenen Player. Dort wiederum werden State-Variablen zur Aufnahme der Player-Daten angelegt.
       
      Das Script erzeugt auch on-Handler um auf Steuerungen über vis und andere Scripte an den State-Variablen reagieren zu können.
       
      Beim Beenden des Scripts werden alle Verbindungen und on-Handler geschlossen.
      
      Das Script ermöglicht die HEOS Player zu steuern, es soll aber nicht die HEOS App ersetzen. 
       
        
      #### Wichtig!
      
      * Im Javascript-Adapter muss in der Instanz-Konfiguration "node-ssdp" mit angegeben werden! Alternativ kann die Bibliothek auch komplett über "npm install node-ssdp" installiert werden.
      * Wenn mit Favoriten (Presets) gearbeitet werden soll, müssen die HEOS-Konto Logindaten in den beiden Konstanten HEOS_USERNAME (EmailAdr) und HEOS_PASSWORD hier im Script in der Konfiguration angegeben werden (so, wie in der HEOS App)!
      * Eine Konfiguration von IP-Adressen und Player-IDs ist nicht notwendig!
      * U.U. kann es notwendig sein das Script nach dem 1.Start zu beenden und nach 30 Sek erneut zu starten, da die Neuanlage der ioBroker States etwas Zeit benötigt. Warnungen sind dabei zu ignorieren. ;-)
      
      #### Updates
       
      ##### v2.0 13.03.2020
      * das Script überprüft nun, ob alle notwendigen states für Heos und HeosPlayer im ioBroker korrekt erzeugt wurden und gibt eine Warnung mit Script-Neustartaufforderung aus, wenn die states nicht vorhanden sind. Dieses ist notwendig, da das Anlegen von states asynchron erfolgt und einige ms dauern kann
      * (WICHTIG!) die states werden nicht mehr in der aktuellen Javascript-Instanz und auch nicht mehr unter der IP des Heos-Players gespeichert, sondern Javascript-Instanzunabhängig unter 0_userdata.0 und seiner Player-ID (pid), da diese sich nicht ändert. Die IP hingegen u.U. schon. Also statt "javascript.X.heos.192_168_2_43" nun als "0_userdata.0.heos.12345678". Wer bereits auf die alten Werte im VIS zugreift, muss dieses im VIS anpassen!  
      * es wurden Befehle/states für die Gruppensteuerung der Heos-Player hinzugefügt. Beim Start werden die Gruppen ausgelesen und in den Player-states des Gruppenleiters (der erste genannte Player) gespeichert. Über dessen states kann die Gruppe gesteuert werden: 
          group_volume: dient der Steuerung der Gruppen-Lautstärke
          group_mute: dient der Steuerung der Gruppen-Mutes
          group_leader: ist true, wenn der Player der Gruppenleiter ist
          group_member: ist true, wenn der Player Mitglied einer Gruppe ist
      * alle 60 Sek wird überprüft, ob noch alle HEOS-Player erreichbar sind bzw. neue/reconnectete hinzugekommen sind. Neue/reconnectete werden der Liste der HEOS-Player hinzugefügt, fehlende werden gestoppt. Da hierzu das HEOS-Netzwerk gefragt wird (get_players Meldung), kann es bis zu 5 Min dauern bis Änderungen erkannt werden. Der neue HEOS-Player-State "connected" wird entsprechend gesetzt
      * jeder HEOS-Player hat einen neuen state "connected", dieser wird nach erfolgreichem Start auf true gesetzt, bei korrektem Beenden des Scripts auf false
      * diverse Filter/Korrekturen aus dem Forum übernommen, vielen dank an withstu
        
        
       #### class Heos
       
       Diese Basisklasse dient 
      
      * dem Erkennen von HEOS Geräten (Playern). Das Erkennen der HEOS Geräte findet via UPD unter Nutzung von node-ssdp statt. node-ssdp muss dazu im Javascript-Adapter in der Konfiguration mit angegeben werden!
      * der Kommunikation über TelNet. Es wird genau eine TelNet Verbindung zu einem HEOS Gerät aufgebaut, dieses reicht die Sendungen und Antworten zentral weiter
      * der Ermittlung von Favoriten (Presets). Für jeden Favorit wird ein ioBroker State heos.presets.n mit entsprechenden Sub-States erzeugt. Zur Nutzung der Presets ist ein SignIn notwendig, hierzu müssen HEOS_USERNAME und HEOS_PASSWORD gesetzt werden.
      * dem Instanziieren der class HeosPlayer je HEOS Gerät. Je HEOS Gerät wird ein ioBroker-State mit der IP-Adresse des Players erzeugt, dieser State erhält diverse Sub-States
        
      ##### State-Variable: Heos
       
      Werden angelegt unter "0_userdata.0.heos."
      
      * connected: true wenn die Verbindung zu mindestens einem HEOS-Player besteht
      * script_version: Version des Scripts, dient dazu Script-Updates zu erkennen
      * last_error: Letzter Fehlertext
      * command(cmd): Hierüber können der Heos-Klasse Befehle übergeben werden, für cmd gilt:
          "connect": Verbindung zu HEOS aufbauen bzw. erneut aufbauen (praktisch ein reset)
          "disconnect": Verbindung zu HEOS beenden
          "load_presets": lädt die Favoriten neu
        
          "group/set_group?pid=<pid1>,<pid2>,...": setzen einer Gruppe, die pids sind die der Player wie sie unter den Objekten für jeden Player abgelegt sind. Bsp: "group/set_group?pid=12345678,12345679". 
       
         "group/set_group?pid=<pid1>" : hebt die Gruppierung des Players mit der pid1 wieder auf. Bsp: "group/set_group?pid=12345678"
         "...": alle anderen cmd-Werte werden "as is" versucht an HEOS zu senden
       
        
      * presets.<n>: Hierunter werden die Favoriten, Presets angelegt. Je Favorit ein Unterordner n=1 bis Anzahl. Darunter befinden sich dann die States, welche den Inhalt der Favoriten aufnehmen:
       
      * image_url (read): Bild des Favoriten 
      * name (read): Name des Favoriten
      * playable (read): Spielbar? true/false
      * type (read): Typ des Favoriten (station, ...)
       
          
         
       #### class HeosPlayer 
       
       Diese Klasse dient
      * der Steuerung genau eines HEOS Gerätes. Hierzu wird die zentrale Telnet Verbindung der class Heos genutzt.
      * dem Erzeugen der ioBroker-States zum Speichern der Geräte-Werte
      * der Auswertung von Antworten der HEOS Geräte und Zuweisung an die entsprechenden ioBroker-States
       
      ##### State-Variable
      
      Werden angelegt unter "0_userdata.0.heos.<pid>"
      
      * connected : true, wenn eine Verbindung besteht, sonst false
      * command(cmd): Hierüber können dem Heos-Player Befehle übergeben werden. Diese werden im Klartext in die State-Variable geschrieben. Getrennt durch das | Zeichen können mehrere hintereinander eingetragen werden. Bsp: Setzen der Lautstärke auf 20 und Abspielen des 1.Favoriten "set_volume&level=20|play_preset&preset=1|set_play_state&state=play". Folgende cmd sind erlaubt:
      
        "set_volume&level=0|1|..|100" : Setzt die gewünschte Lautstärke 
        "set_play_state&state=play|pause|stop" : Startet und stoppt die Wiedergabe
        "set_play_mode&repeat=on_all|on_one|off&shuffle=on|off": Setzt Wiederholung und Zufallsweidergabe
        "set_mute&state=on|off" : Stumm schalten oder nicht
        "volume_down&step=1..10" : Lautstärke verringern um   
        "volume_up&step=1..10"  : Lauststäre erhöhen um
        "play_next"  : Nächsten Titel spielen
        "play_previous" : Vorherigen Titel spielen
        "play_preset&preset=1|2|..|n" : Favorit Nr n abspielen
        "play_stream&url=url_path" : URL-Stream abspielen
       
      * cur_pos (read) : lfd. Position der Wiedergabe in [Sek]
      * cur_pos_MMSS (read) : lfd. Position der Wiedergabe im Format MM:SS
      * duration (read) : Länge des aktuellen Titels in [Sek]
      * duration_MMSS (read) : Länge des aktuellen Titels im Format MM:SS
      * ip (read): IP-Adresse des HEOS Players
      * last_error (read): Text des letzten Fehlers, der vom Player gesendet wurde. Wird bei jedem neuen Befehl zurückgesetzt. Wenn man bspw. versucht eine Wiedergabe über Amazon o.ä. zu starten und es gibt aber keine Verbindung dahin, steht hier der Fehlertext drin
      * model (read): Modell des HEOS Players
      * mute (read write): Boolsche Variable, die anzeigt ob der Player gemutet (Stumm geschaltet) wurde. Hierüber kann auch ein mute gesetzt werden
      * name (read): Name des HEOS Players
      * now_playing_media_... (read) : Eine Gruppe von States, in welchen Infos über den aktuellen Titel gespeichert werden, wird automatisch aktualisiert. 
      * pid (read): Player-ID des HEOS Players
      * play_mode_repeat (read write) : Repeat-Modus der Wiedergabe. Mögliche Werte: on_all|on_one|off  
      * play_mode_shuffle (read write) : Zufallswiedergabe true/false
      * play_state (read write): Zustand des Players. Mögliche Werte play|pause|stop
      * serial (read): Seriennummmer des HEOS Players
      * volume (read write): Lautstärke im Bereich 0 - 100. 
      * group_leader : Ist Gruppenleiter
      * group_member : Ist Gruppenmitglied
      * group_pid : Player pids in der Gruppe
      * group_volume : Lautstärke wenn Gruppen-Leiter
      * group_name : Name der Gruppe
      * group_mute : Gruppe gemutet?
      
       
      #### Weiterführende Links
      
      * HEOS CLI Protokoll: http://rn.dmglobal.com/euheos/HEOS_CLI_ProtocolSpecification.pdf
      * http://forum.iobroker.net/viewtopic.php?f=30&t=5693&p=115554#p115554
       
       
      (c) Uhula, MIT License, no warranty, use on your own risc
       
      */
      
      /****************************
       * Konfiguration
       ****************************/
       
      const HEOS_USERNAME = '';
      const HEOS_PASSWORD = '';
      
      
      /****************************
       * ab hier nichts mehr ändern ;-) 
       ****************************/
      
      var net = require('net');
      
      const stateDISCONNECTED = 0;
      const stateSEARCHING = 1;
      const stateCONNECTING = 2;
      const stateCONNECTED = 3;
      const SCRIPTVERSION = '2.0/2020-03-13';
      
      /********************
       * class Heos
       ********************/
      class Heos  {
      
      logDebug(msg) { console.debug('[Heos] '+msg); }
      log(msg) { console.log('[Heos] '+msg); }
      logWarn(msg) { console.warn('[Heos] '+msg); }
      logError(msg) { console.error('[Heos] '+msg); }
      
      constructor() {
          this.init();
          this.states = [
              { id:"command",        common:{name:"Kommando für HEOS Aufrufe"}                   },
              { id:"connected",      common:{name:"Verbunden?",                     write:false, def:false } },
              { id:"last_error",     common:{name:"Letzte Fehler",                  write:false} },
              { id:"script_version", common:{name:"Installierte Script-Version", write:false } }
          ];
          // beim 1.Start nur die States erzeugen
          if ( !this.existState("script_version") || (this.getState('script_version').val!=SCRIPTVERSION) ) {
              this.installed = false;
              this.logWarn('creating HEOS states for version '+SCRIPTVERSION+', please start script again');
              // Anlage der States 
              for (var s=0; s<this.states.length; s++) {
                  this.setState( this.states[s].id );
              }
              this.setState('script_version', SCRIPTVERSION);
          }
          else {   
              this.installed = true;
              on({id: this.statePath+'command', change: "any"}, (obj) => {
                      this.executeCommand( obj.state.val );
                  });
          }
      }
      
      
      
      // Initialisierung
      init() {
          this.statePath = '0_userdata.0.heos.';
          this.players = [];
          this.heartbeatInterval = undefined;
          this.heartbeatTimeout = undefined;
          this.ssdpSearchInterval = undefined;
          this.getPlayersInterval = undefined;
          this.net_client = undefined;
          this.nodessdp_client = undefined;
      
          this.ip='';
          this.msgs = [];
          this.lastResponse = '';
          this.state = stateDISCONNECTED;
          this.unfinishedResponses = '';
          this.ssdpSearchTargetName = 'urn:schemas-denon-com:device:ACT-Denon:1';
      }
      
      
      // über den $-Operator nachsehen, ob der state bereits vorhanden ist
      // getState().notExists geht auch, erzeugt aber Warnmeldungen!
      existState(id) {
          return ( $(this.statePath+id).length==0?false:true);
      }
      
      // wrapper
      getState(id) {
          return getState(this.statePath + id);
      }
      
      // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
      // wenn er noch nicht da ist
      setState(id,value) {
          if ( !this.existState(id) ) this.createState(id, value, undefined);
          else setState( this.statePath + id, value);
      }
      
      // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
      // vorhanden sind (wenn der common-Parameter leer ist)
      createState(id, value, common) {
          if ( !this.existState(id) ) {
              if (common===undefined) {
                  // id im states-Array suchen
                  for (var i=0; i<this.states.length; i++) { 
                      if (this.states[i].id==id) {
                          if (this.states[i].hasOwnProperty('common'))
                              common = this.states[i].common;
                         break;
                      }   
                  }
              }
              if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
              // unter "0_userdata.0"
              let obj = {};
              obj.type = 'state';
              obj.native = {};
              obj.common = common;
              setObject(this.statePath + id, obj, (err) => {
                      if (err) {
                          this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                      } else { 
                          this.log('state "' + this.statePath + id + '" created');
                      }
              });
            
              // value zeitversetzt setzen        
              setTimeout( setState, 3000, this.statePath + id, value );
          }
      }
      
      /** Verbindung zum HEOS System herstellen
       **/
      connect() { 
          if ( !this.installed ) return;
      
          try {
              this.log("searching for HEOS devices ...")
              this.setState( "connected", false );
              this.state = stateSEARCHING;
              const NodeSSDP = require('node-ssdp').Client;
      	    this.nodessdp_client = new NodeSSDP();
      	    this.nodessdp_client.explicitSocketBind = true;
      	    this.nodessdp_client.on('response', (headers, statusCode, rinfo) => this.onNodeSSDPResponse(headers, statusCode, rinfo) );
              this.nodessdp_client.on('error', error => {	this.nodessdp_client.close(); this.logError(error); });
              this.nodessdp_client.search(this.ssdpSearchTargetName);
              this.ssdpSearchInterval = setInterval(() => {
                  this.log("still searching for HEOS devices ...")
                  this.nodessdp_client.search(this.ssdpSearchTargetName);
              }, 30000);
          } catch(err) { this.logError( 'connect: '+err.message ); } 
          
      }
      
      
      /** Alle Player stoppen und die TelNet Verbindung schließen 
       **/
      disconnect() {
          this.log('disconnecting from HEOS ...');
          unsubscribe(this.statePath.substr(0,this.statePath.length-1));
      
          this.stopHeartbeat();
          this.stopPlayers();
      
          if (typeof this.net_client!=='undefined') {
              this.registerChangeEvents( false );
              this.net_client.destroy();
              this.net_client.unref();
          }
          if (typeof this.nodessdp_client!=='undefined') {
              this.nodessdp_client.stop();
          }
          this.setState( "connected", false );
          this.log('disconnected from HEOS');
      }
      
      reconnect(){
          this.log('reconnecting to HEOS ...');
          this.disconnect();
          this.init();
          this.connect();
      }
      
      executeCommand(cmd) {
      //l('command: '+cmd);
          switch (cmd) {
              case 'load_presets' :
                  this.getMusicSources();
                  break;
              case 'group/get_groups' :
                  this.getGroups();
                  break;
              case 'connect' :
                  this.disconnect();
                  this.init();
                  this.connect();
                  break;
              case 'disconnect' :
                  this.disconnect();
                  break;
              default:
                  if (this.state == stateCONNECTED) {
                      this.msgs.push( 'heos://'+cmd+'\n' );
                      this.sendNextMsg();
                  }
          
          }
      }
      /** es wurde mindestens ein Player erkannt, nun über dessen IP alle bekannten HEOS Player
       *  durch senden von "player/get_players" ermitteln
       */
      onNodeSSDPResponse(headers, statusCode, rinfo) { try {
          // rinfo {"address":"192.168.2.225","family":"IPv4","port":53871,"size":430}
          if (typeof this.net_client=='undefined') {
              if(headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                  this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
              } else {
                  if (this.ssdpSearchInterval!==undefined) {
                      clearInterval(this.ssdpSearchInterval);
                      this.ssdpSearchInterval = undefined;
                  }
      
                  this.ip = rinfo.address;
                  this.log('connecting to HEOS ('+this.ip+') ...');
                  this.net_client = net.connect({host:this.ip, port:1255});
                  this.net_client.setKeepAlive(true, 5000);
                  this.net_client.setNoDelay(true);
                  this.net_client.setTimeout(15000);
      
                  this.state = stateCONNECTING;
      
                  this.net_client.on('error',(error) => {
                      this.logError(error);
                      this.reconnect();
                  }); 
          
                  this.net_client.on('connect',  () => {
                      this.setState( "connected", true );
                      this.state = stateCONNECTED;
                      this.log('connected to HEOS ('+this.ip+')');
                      this.getPlayers();
                      this.registerChangeEvents( true );
                      this.signIn();
                      this.getMusicSources();
                      this.getGroups();
                      this.startHeartbeat();
                  });
              
                  // Gegenseite hat die Verbindung geschlossen 
                  this.net_client.on('end',  () => {              
                      this.logWarn('HEOS closed the connection to '+this.ip);
                      this.state = stateDISCONNECTED;
                      this.reconnect();
                  });
      
                  // timeout
                  this.net_client.on('timeout',  () => {              
                      this.logWarn('Timeout trying connect to '+this.ip);
                      this.state = stateDISCONNECTED;
                      this.reconnect();
                  });
      
                  // Datenempfang
                  this.net_client.on('data', (data) => this.onData(data)  );
              }
          }
      } catch(err) { this.logError( 'onNodeSSDPResponse: '+err.message ); } }
      
      setLastError(err) {
          this.logWarn(err);
          /*
          var val = getState(this.statePath+'last_error').val;
          var lines = val.splitt('\n');
          if ( lines.length > 4)
              lines.pop();
          lines.unshift(err+'\n');
      l(lines);       
          this.setState('last_error', lines.toString());
          */    
      }
      
      
      /** es liegen Antwort(en) vor
       * 
       * {"heos": {"command": "browse/browse", "result": "success", "message": "sid=1028&returned=9&count=9"}, 
       *    "payload": [
       *        {"container": "no", "mid": "s25529", "type": "station", "playable": "yes", "name": "NDR 1 Niedersachsen (Adult Hits)", "image_url": "http://cdn-profiles.tunein.com/s25529/images/logoq.png?t=154228"}, 
       *        {"container": "no", "mid": "s56857", "type": "station", "playable": "yes", "name": "NDR 2 Niedersachsen 96.2 (Top 40 %26 Pop Music)", "image_url": "http://cdn-profiles.tunein.com/s56857/images/logoq.png?t=154228"}, 
       *        {"container": "no", "mid": "s24885", "type": "station", "playable": "yes", "name": "NDR Info", "image_url": "http://cdn-profiles.tunein.com/s24885/images/logoq.png?t=1"}, {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
       *        {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}, 
       *        {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
       *        {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk"
       **/
      onData(data) {  try {
          data = data.toString();
          data=data.replace(/[\n\r]/g, '');    // Steuerzeichen "CR" entfernen   
          // es können auch mehrere Antworten vorhanden sein! {"heos": ... } {"heos": ... }
          // diese nun in einzelne Antworten zerlegen
          data = this.unfinishedResponses + data;
          this.unfinishedResponses = '';
          
          data=data.replace(/{"heos":/g, '|{"heos":');    
          var responses = data.split('|');
          responses.shift();
          for (var r=0; r<responses.length; r++ ) if(responses[r].trim().length > 0) {
              try {
                  JSON.parse(responses[r]); // check ob korrektes JSON Array
                  this.parseResponse(responses[r]);
              } catch(e) {
                  this.logDebug('onData: invalid json (error: ' + e.message + '): ' + responses[r]);
                  this.unfinishedResponses += responses[r];
              }
          }
          // wenn weitere Msg zum Senden vorhanden sind, die nächste senden
          if (this.msgs.length>0)
              this.sendNextMsg();
      } catch(err) { this.logError( 'onData: '+err.message ); } }
      
      /** Antwort(en) verarbeiten. Sich wiederholende Antworten ignorieren
       **/
      parseResponse (response) { try {
          if (response == this.lastResponse || response.indexOf("command under process") > 0 )
              return
          this.lastResponse = response;        
          
          var jmsg;
          var i;
          var jdata = JSON.parse(response);
          if ( !jdata.hasOwnProperty('heos') || !jdata.heos.hasOwnProperty('command') || !jdata.heos.hasOwnProperty('message') ) 
              return;
      
          // msg auswerten
          try {
              jmsg = '{"' + decodeURI(jdata.heos.message).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"').replace(/\s/g,'_') + '"}';
              jmsg = JSON.parse(jmsg);
          } catch(err) {
              jmsg = {};
          }
      
          this.logDebug('parseResponse: '+response); 
      
          // result ?
          var result = 'success';
          if (jdata.heos.hasOwnProperty('result') ) result = jdata.heos.result;
          if ( result!='success' ) { 
              this.setLastError('result='+result+', '+jmsg.text);
          }
      
          // cmd auswerten
          var cmd = jdata.heos.command.split('/');
          var cmd_group = cmd[0];
          cmd = cmd[1];
          switch (cmd_group) {
              case 'system':
                  switch(cmd) {
                      case 'heart_beat':
                          this.resetHeartbeatTimeout();
                          break;
                  }
                  break;
              case 'event':
                  switch (cmd) {
                      case 'group_volume_changed' :
                      // "heos": {"command": "event/group_volume_changed ","message": "gid='group_id'&level='vol_level'&mute='on_or_off'"}
                      this.getGroups();
                      break;
                  }
                  break;
              case 'player':
                  switch (cmd) {
                          // {"heos": {"command": "player/get_players", "result": "success", "message": ""}, 
                          //  "payload": [{"name": "HEOS Bar", "pid": 1262037998, "model": "HEOS Bar", "version": "1.430.160", "ip": "192.168.2.225", "network": "wifi", "lineout": 0, "serial": "ADAG9170202780"}, 
                          //              {"name": "HEOS 1 rechts", "pid": -1746612370, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.201", "network": "wifi", "lineout": 0, "serial": "AMWG9170934429"}, 
                          //              {"name": "HEOS 1 links", "pid": 68572158, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.219", "network": "wifi", "lineout": 0, "serial": "AMWG9170934433"}
                          //             ]}
                      case 'get_players' :
                          if (jdata.hasOwnProperty('payload')) {
                              if (jdata.payload.length != this.players.length) {
                                  this.stopPlayers();
                                  this.players = [];
                                  for (i=0; i<jdata.payload.length; i++) {
                                      var player = jdata.payload[i];
                                      this.players.push(player);
                                  }
                                  this.startPlayers();
                              } 
                          }
                          break;
                  }
                  break;
      
              // {"heos": {"command": "browse/get_music_sources", "result": "success", "message": ""}, 
              //  "payload": [{"name": "Amazon", "image_url": "https://production...png", "type": "music_service", "sid": 13}, 
              //              {"name": "TuneIn", "image_url": "https://production...png", "type": "music_service", "sid": 3}, 
              //              {"name": "Local Music", "image_url": "https://production...png", "type": "heos_server", "sid": 1024}, 
              //              {"name": "Playlists", "image_url": "https://production...png", "type": "heos_service", "sid": 1025}, 
              //              {"name": "History", "image_url": "https://production...png", "type": "heos_service", "sid": 1026}, 
              //              {"name": "AUX Input", "image_url": "https://production...png", "type": "heos_service", "sid": 1027}, 
              //              {"name": "Favorites", "image_url": "https://production...png", "type": "heos_service", "sid": 1028}]}
              case 'browse':
                  switch (cmd) {
                      case 'get_music_sources' :
                          if ( (jdata.hasOwnProperty('payload')) ) {
                              for (i=0; i<jdata.payload.length; i++) {
                                  var source = jdata.payload[i];
                                  if (source.name=='Favorites') {
                                      this.browse(source.sid);
                                  }
                              }
                          }
      
                          break;
                          
      	    // {"heos": {"command": "browse/browse", "result": "success", "message": "pid=1262037998&sid=1028&returned=5&count=5"}, 
      	    //  "payload": [{"container": "no", "mid": "s17492", "type": "station", "playable": "yes", "name": "NDR 2 (Adult Contemporary Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s17492q.png"}, 
      	    //              {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
      	    //              {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk", "type": "station", "playable": "yes", "name": "Ed Sheeran", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/EdSheeran._SX200_SY200_.jpg"}, 
      	    //              {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
      	    //              {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}], 
      	    //  "options": [{"browse": [{"id": 20, "name": "Remove from HEOS Favorites"}]}]}                    
                      case 'browse' :
                          if ( (jdata.hasOwnProperty('payload')) ) {
                              for (i=0; i<jdata.payload.length; i++) {
                                  var preset = jdata.payload[i];
                                  this.createState( 'presets.'+(i+1)+'.name', preset.name, {name: 'Favoritenname ' });
                                  this.createState( 'presets.'+(i+1)+'.playable', (preset.playable=='yes'?true:false), {name: 'Favorit ist spielbar' });
                                  this.createState( 'presets.'+(i+1)+'.type', preset.type, {name: 'Favorittyp' });
                                  this.createState( 'presets.'+(i+1)+'.image_url', preset.image_url, {name: 'Favoritbild' });
                              }
                          }
                          break;
                  }     
                  break;
      
              case 'group':
      //l('group: '+response);
                  switch (cmd) {
                        // { "heos":{"command":"player/set_group","result":"success",
                        //           "message": "gid='new group_id'&name='group_name'&pid='player_id_1, player_id_2,…,player_id_n'
                        //          } 
                        // }
                      case 'set_group' :
                          this.setGroup( jmsg );
                          break;
      
                      // { "heos": {"command":"group/get_volume","result":"success","message": "gid='group_id'&level='vol_level'"}
                      case 'get_volume':
                          if ( jmsg.hasOwnProperty('gid') ) {
                              if ( jmsg.hasOwnProperty('level') ) {
                                  this.setState( jmsg.gid+'.group_volume', jmsg.level);
                              }
                          }
                          break;
      
                      // { "heos": {"command":"group/get_mute","result":"success","message": "gid='group_id'&state='on_or_off'"}
                      case 'get_mute':
                          if ( jmsg.hasOwnProperty('gid') ) {
                              if ( jmsg.hasOwnProperty('state') ) {
                                  this.setState( jmsg.gid+'.group_mute', (jmsg.state=='on' ? true : false));
                              }
                          }
                          break;
      
      
                      // { "heos": { "command": "player/get_groups", "result": "success", "message": "" },
                      //   "payload": [{"name":"'group name 1'", "gid": "group id 1'",
                      //                "players":[{"name":"player name 1","pid":"'player id1'","role":"player role 1 (leader or member)'"},
                      //                           {"name":"player name 2","pid":"'player id2'","role":"player role 2 (leader or member)'"} 
                      //                          ]
                      //               },
                      //               {"name":"'group name 2'","gid":"group id 2'",
                      //                "players":[{"name":"player name ... 
                      case 'get_groups' :
                          // bisherige groups leeren
                          var objs = $(this.statePath+'*.group_name');
                          for (var o=0; o<objs.length; o++) setState(objs[o], 'no group');
                          objs = $(this.statePath+'*.group_leader');
                          for (var o=0; o<objs.length; o++) setState(objs[o], false);
                          objs = $(this.statePath+'*.group_member');
                          for (var o=0; o<objs.length; o++) setState(objs[o], false);
                          objs = $(this.statePath+'*.group_pid');
                          for (var o=0; o<objs.length; o++) setState(objs[o], '');
      
                          // payload mit den groups auswerten
                          if ( (jdata.hasOwnProperty('payload')) ) {
                              for (i=0; i<jdata.payload.length; i++) {
                                  var group = jdata.payload[i];
                                  var players = group.players;
                                  // Player IDs addieren. Hinweis: "leader" ist nicht immer der 1.Playereintrag
                                  group.pid = "";
                                  for (var p=0; p<players.length; p++) {
                                      if ( players[p].role == 'leader' )
                                          group.pid = players[p].pid + (group.pid.length>0?",":"") + group.pid;
                                      else
                                          group.pid = group.pid + (group.pid.length>0?",":"") + players[p].pid;
                                  }
                                  this.setGroup(group);
                              }
                          }
                          break;
                          
                  }     
                  break;
      
      
              case 'system':
                  switch (cmd) {
                      case 'sign_in' :
                          this.log('signed in: '+jdata.heos.result);
                          break;
                  }     
                  break;
          }
      
      
          // an die zugehörigen Player weiterleiten
          if ( jmsg.hasOwnProperty('pid') ) {
              for (i=0; i<this.players.length; i++)
                  if (jmsg.pid==this.players[i].heosPlayer.pid) {
                      this.players[i].heosPlayer.parseResponse (jdata, jmsg, cmd_group, cmd);
                      break;
                  }
          }
      
          
      } catch(err) { this.logError( 'parseResponse: '+err.message+'\n '+response ); } }
      
      
      // sucht die zur pid passenden player-Insanz
      sendCommandToPlayer(objID, cmd ) {
         // aus der objID die pid holen
         // objID = javascript.1.heos.394645376.command
         objID = objID.split('.');
         var pid = objID[3];
         for (var p=0; p<this.players.length; p++ ) 
             if (this.players[p].pid == pid ) {
                 this.players[p].heosPlayer.sendCommand( cmd );
                 break;
             }
      } 
      
      // Für die gefundenen HEOS Player entsprechende class HeosPlayer Instanzen bilden 
      startPlayers() { try {
         this.stopPlayers();
          let i=0;
          for (i=0; i<this.players.length; i++) {
             this.players[i].heosPlayer = new HeosPlayer( this, this.players[i]  );
          }
      
          // alle 30 Sekunden auf neue Player untersuchen
          this.getPlayersInterval = setInterval(() => {
              this.getPlayers();
          }, 30000);
      
      /*
          // Events setzen
          for (i=0; i<this.players.length; i++) {
              let heosPlayer = this.players[i].heosPlayer;
              heosPlayer.onHandler = [];
              // on-Event für command
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'command', change: "any"}, (obj) => {
                  this.sendCommandToPlayer( obj.id, obj.state.val ) 
              }));
      
              // on-Event für volume (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'volume', change:'ne', ack:false }, (obj) => {
                  this.sendCommandToPlayer( obj.id, 'set_volume&level='+obj.state.val );
              }));
              // on-Event für mute (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'mute', change: 'ne', ack:false}, (obj) => {
                  this.sendCommandToPlayer( obj.id, 'set_mute&state='+ (obj.state.val === true ? 'on' : 'off') );
              }));
              // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'play_mode_shuffle', change: 'ne', ack:false}, (obj) => {
                  this.sendCommandToPlayer( obj.id, 'set_play_mode&shuffle='+ (obj.state.val === true ? 'on' : 'off') );
              }));
              // on-Event für play_state (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'play_state', change: 'ne', ack:false}, (obj) => {
                  this.sendCommandToPlayer( obj.id, 'set_play_state&state='+ obj.state.val );
              }));
      
              // on-Event für group-volume (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'group_volume', change:'ne', ack:false }, (obj) => {
                  // "id":"javascript.1.heos.-1746612370.group_volume"
                  var id = obj.id.split('.');
                  this.executeCommand( 'group/set_volume?gid='+id[3]+'&level='+obj.state.val );
              }));
      
              // on-Event für group-mute (nur wenn ack=false, also über vis)
              heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'group_mute', change:'ne', ack:false }, (obj) => {
                  // "id":"javascript.1.heos.-1746612370.group_volume"
                  var id = obj.id.split('.');
                  this.executeCommand( 'group/set_mute?gid='+id[3]+'&state='+(obj.state.val===true ? 'on':'off') );
                     }));
          }    
      */
      } catch(err) { this.logError( 'startPlayers: '+err.message ); } }
      
      //
      stopPlayers() { try {
          if (this.getPlayersInterval!==undefined) {
              clearInterval(this.getPlayersInterval);
              this.getPlayersInterval = undefined;
          }
          for (let i=0; i<this.players.length; i++) {
              let heosPlayer = this.players[i].heosPlayer;
              if (heosPlayer)
                  heosPlayer.stopPlayer();
              // player leeren
              this.players[i].heosPlayer = undefined;
          }
      } catch(err) { this.logError( 'stopPlayers: '+err.message ); } }
      
      // setzen der Werte einer Group
      setGroup(group) {
          if ( group.hasOwnProperty('pid') ) {    
              // in den Playern den Groupstatus setzen
              var pids = group.pid.split(',');
                
              for (var i=0; i<pids.length; i++) {
                  this.setState(pids[i]+'.group_name', (group.hasOwnProperty('name')?group.name:''));
                  this.setState(pids[i]+'.group_pid', group.pid);
                  this.setState(pids[i]+'.group_leader', (i==0) && (pids.length>1) );
                  this.setState(pids[i]+'.group_member', (pids.length>1));
              }
                  
              if ( group.hasOwnProperty('gid') ) {   
                  // volume und mute dazu holen
                  this.executeCommand("group/get_volume?gid="+group.gid);
                  this.executeCommand("group/get_mute?gid="+group.gid);
              }
          }
      
      }
      
      getPlayers() {
          if (this.state == stateCONNECTED) {
              this.msgs.push( 'heos://player/get_players\n' );
              this.sendNextMsg();
          }
      }
      
      registerChangeEvents( b ) {
          if (this.state == stateCONNECTED) {
              if (b) this.msgs.push( 'heos://system/register_for_change_events?enable=on' );
              else this.msgs.push( 'heos://system/register_for_change_events?enable=off' );
              this.sendNextMsg();
          }
      }
      
      signIn() {
          if (this.state == stateCONNECTED) {
              // heos://system/sign_in?un=heos_username&pw=heos_password
              this.msgs.push( 'heos://system/sign_in?un='+HEOS_USERNAME+'&pw='+HEOS_PASSWORD );
              this.sendNextMsg();
          }
      }
      
      getMusicSources() {
          if (this.state == stateCONNECTED) {
              // heos://browse/get_music_sources
              this.msgs.push( 'heos://browse/get_music_sources' );
              this.sendNextMsg();
          }
          
      }
      
      getGroups() {
          if (this.state == stateCONNECTED) {
              // heos://group/get_groups
              this.msgs.push( 'heos://group/get_groups' );
              this.sendNextMsg();
          }
          
      }
      
      startHeartbeat(){
          this.logDebug("start heartbeat interval");
          this.heartbeatInterval = setInterval(() => {
              this.logDebug("heartbeat")
              this.msgs.push( 'heos://system/heart_beat' );
              this.sendNextMsg();
              if (this.heartbeatTimeout==undefined) {
                  this.heartbeatTimeout = setTimeout(() => {
                      this.log("heartbeat timeout");
                      this.reconnect();
                  }, 60000);
              }
          }, 15000);
      }
      
      resetHeartbeatTimeout(){
          this.logDebug("reset heartbeat timeout");
          if (this.heartbeatTimeout!==undefined) {
              clearTimeout(this.heartbeatTimeout);
              this.heartbeatTimeout = undefined;
          }
      }
      
      stopHeartbeat(){
          this.logDebug("stop heartbeat interval");
          if (this.heartbeatInterval!==undefined) {
              clearInterval(this.heartbeatInterval);
              this.heartbeatInterval = undefined;
          }
          this.resetHeartbeatTimeout();
      }
      
      browse(sid) {
          if (this.state == stateCONNECTED) {
              // heos://browse/browse?sid=source_id
              this.msgs.push( 'heos://browse/browse?sid='+sid );
              this.sendNextMsg();
          }
          
      }
      
      
      sendNextMsg () {
          if (this.msgs.length>0) {
              var msg = this.msgs.shift();
              this.sendMsg(msg);
          }
      }
      
      // Nachricht an player senden
      sendMsg (msg) {
          this.net_client.write(msg + "\n");
          this.logDebug("data sent: "+ msg);
      }
      
      
      } // end of class Heos
      
      /********************
       * class HeosPlayer
       ********************/
      
      class HeosPlayer  {
      
      logDebug(msg) { console.debug('[HeosPlayer '+this.pid+'] '+msg); }
      log(msg) { console.log('[HeosPlayer '+this.pid+'] '+msg); }
      logWarn(msg) { console.warn('[HeosPlayer '+this.pid+'] '+msg); }
      logError(msg) { console.error('[HeosPlayer '+this.pid+'] '+msg); }
      
      constructor(heos, player) {
          this.heos = heos;
          this.ip = player.ip;
          this.name = player.name;
          this.pid = player.pid;
          this.model = player.model;
          this.serial = player.serial;
          this.onHandler = [];
      
      //    this.statePath = 'javascript.'+instance+'.heos.'+this.ip.replace(/\./g,'_')+".";
          this.statePath = '0_userdata.0.heos.'+this.pid+".";
      
          this.log('creating HEOS player with pid '+this.pid+' ('+this.ip+')');
      
          this.states = [
              { id:"connected",                   common:{name:"Verbunden?"} },
              { id:"command",                     common:{name:"Befehl an Heos Player senden"} },
              { id:"ip",                          common:{name:"IP-Adresse", write:false} },
              { id:"pid",                         common:{name:"Player-ID", write:false} },
              { id:"name",                        common:{name:"Name des Players", write:false} },
              { id:"model",                       common:{name:"Modell des Players", write:false} },
              { id:"serial",                      common:{name:"Seriennummer des Players", write:false} },
              { id:"last_error",                  common:{name:"Letzte Fehler", write:false} },
              { id:"volume",                      common:{name:"Aktuelle Lautstärke"} },
              { id:"mute",                        common:{name:"Mute aktiviert?"} },
              { id:"play_state",                  common:{name:"Aktueller Wiedergabezustand"} },
              { id:"play_mode_repeat",            common:{name:"Wiedergabewiederholung"} },
              { id:"play_mode_shuffle",           common:{name:"Zufällige Wiedergabe"} },
              { id:"now_playing_media_type",      common:{name:"Aktuelle Wiedergabemedium", write:false} },
              { id:"now_playing_media_song",      common:{name:"Aktuelles Lied", write:false} },
              { id:"now_playing_media_station",   common:{name:"Aktuelle Station", write:false} },
              { id:"now_playing_media_album",     common:{name:"Aktuelle Wiedergabemedium", write:false} },
              { id:"now_playing_media_artist",    common:{name:"Aktueller Artist", write:false} },
              { id:"now_playing_media_image_url", common:{name:"Aktuelles Coverbild", write:false} },
              { id:"now_playing_media_album_id",  common:{name:"Aktuelle Album-ID", write:false} },
              { id:"now_playing_media_mid",       common:{name:"Aktuelle mid", write:false} },
              { id:"now_playing_media_qid",       common:{name:"Aktuelle qid", write:false} },
              { id:"cur_pos",                     common:{name:"lfd. Position"} },
              { id:"duration",                    common:{name:"Dauer", write:false} },
              { id:"cur_pos_MMSS",                common:{name:"lfd. Position MM:SS"} } ,
              { id:"duration_MMSS",               common:{name:"Dauer MM:SS", write:false} },
              { id:"group_leader",                common:{name:"Ist Gruppenleiter", write:false} },
              { id:"group_member",                common:{name:"Ist Gruppenmitglied", write:false} },
              { id:"group_pid",                   common:{name:"PlayerIDs in der Gruppe", write:false} },
              { id:"group_volume",                common:{name:"Lautstärke wenn Gruppen-Leiter"}},
              { id:"group_name",                  common:{name:"Name der Gruppe", write:false} } ,
              { id:"group_mute",                  common:{name:"Gruppe gemutet?"} },
              { id:"script_version",              common:{name:"Installierte Script-Version", write:false} }
          ];
          // beim 1.Start die states erzeugen
          if ( !this.existState("script_version") || this.getState('script_version').val!=SCRIPTVERSION ) {
              this.installed = false;
              this.logWarn('creating HEOS player states for version '+SCRIPTVERSION+', please start script again');
              // states erzeugen
              for (var s=0; s<this.states.length; s++) {
                  this.setState( this.states[s].id);
              }
              this.setState('script_version', SCRIPTVERSION);
          }
          else {
              // Initialisierung der States nach 5 Sek
              setTimeout(() => {
                  this.setState('ip',this.ip);
                  this.setState('name',this.name);
                  this.setState('pid',this.pid);
                  this.setState('model',this.model);
                  this.setState('serial',this.serial);
                  this.sendCommand('get_play_state|get_play_mode|get_now_playing_media|get_volume');
              }, 5000 );
              setTimeout(() => {
                  this.startPlayer();
              }, 10000 );
              this.installed = true;
          }
      }
      
      // über den $-Operator nachsehen, ob der state bereits vorhanden ist
      // getState().notExists geht auch, erzeugt aber Warnmeldungen!
      existState(id) {
          return ( $(this.statePath+id).length==0?false:true);
      }
      
      // wrapper
      getState(id) {
          return getState(this.statePath + id);
      }
      
      // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
      // wenn er noch nicht da ist
      setState(id,value) {
          if ( !this.existState(id) ) this.createState(id, value, undefined);
          else setState( this.statePath + id, value);
      }
      
      // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
      // vorhanden sind (wenn der common-Parameter leer ist)
      createState(id, value, common) {
          if ( !this.existState(id) ) {
              if (common===undefined) {
                  // id im states-Array suchen
                  for (var i=0; i<this.states.length; i++) { 
                      if (this.states[i].id==id) {
                          if (this.states[i].hasOwnProperty('common'))
                              common = this.states[i].common;
                         break;
                      }   
                  }
              }
              if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
              // unter "0_userdata.0"
              let obj = {};
              obj.type = 'state';
              obj.native = {};
              obj.common = common;
              setObject(this.statePath + id, obj, (err) => {
                      if (err) {
                          this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                      } else { 
                          this.log('state "' + this.statePath + id + '" created');
                      }
              });
            
              // value zeitversetzt setzen        
              setTimeout( setState, 3000, this.statePath + id, value );
          }
      }
      
      
      startPlayer() { try {
          this.log('starting HEOS player with pid '+this.pid+' ('+this.ip+')');
          this.onHandler = [];
          // on-Event für command
          this.onHandler.push( on({id: this.statePath+'command', change: "any"}, (obj) => {
              this.executeCommand( obj.id, obj.state.val ) 
          }));
      
          // on-Event für volume (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'volume', change:'ne', ack:false }, (obj) => {
              this.executeCommand( obj.id, 'set_volume&level='+obj.state.val );
          }));
          // on-Event für mute (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'mute', change: 'ne', ack:false}, (obj) => {
              this.executeCommand( obj.id, 'set_mute&state='+ (obj.state.val === true ? 'on' : 'off') );
          }));
          // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'play_mode_shuffle', change: 'ne', ack:false}, (obj) => {
              this.executeCommand( obj.id, 'set_play_mode&shuffle='+ (obj.state.val === true ? 'on' : 'off') );
          }));
          // on-Event für play_state (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'play_state', change: 'ne', ack:false}, (obj) => {
              this.executeCommand( obj.id, 'set_play_state&state='+ obj.state.val );
          }));
      
          // on-Event für group-volume (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'group_volume', change:'ne', ack:false }, (obj) => {
              // "id":"javascript.1.heos.-1746612370.group_volume"
              var id = obj.id.split('.');
              this.executeCommand( 'group/set_volume?gid='+id[3]+'&level='+obj.state.val );
          }));
      
          // on-Event für group-mute (nur wenn ack=false, also über vis)
          this.onHandler.push( on({id: this.statePath+'group_mute', change:'ne', ack:false }, (obj) => {
              // "id":"javascript.1.heos.-1746612370.group_volume"
              var id = obj.id.split('.');
              this.heos.executeCommand( 'group/set_mute?gid='+id[3]+'&state='+(obj.state.val===true ? 'on':'off') );
          }));
      
          this.setState('connected', true);
      } catch(err) { this.logError( 'startPlayer: '+err.message ); } }
      
      // sucht die zur pid passenden player-Insanz
      executeCommand(objID, cmd ) {
          // aus der objID die pid holen
          // objID = javascript.1.heos.394645376.command
          objID = objID.split('.');
          var pid = objID[3];
          if (this.pid == pid ) {
              this.sendCommand( cmd );
          }
       } 
       
      
      stopPlayer() { try {
          this.log('stopping HEOS player with pid '+this.pid+' ('+this.ip+')');
      
          // events unsubcribe
          for (let i=0; i<this.onHandler.length; i++) {
              if (this.onHandler[i]!==undefined) unsubscribe(this.onHandler[i]);
          }
          this.onHandler = [];
          // connected zurücksetzen
          this.setState( "connected", false );
      } catch(err) { this.logError( 'stopPlayer: '+err.message ); } }
      
      /** wandelt einen sek Wert in MM:SS Darstellung um
       **/
      toMMSS (s) {
          var sec_num = parseInt(s, 10); 
          var minutes = Math.floor(sec_num  / 60);
          var seconds = sec_num - (minutes * 60);
          if (seconds < 10) {seconds = "0"+seconds;}
          return minutes+':'+seconds;
      }
      
      setLastError(err) { try {
          this.logWarn(err);
          let val = this.getState('last_error').val;
          let lines = val.splitt('\n');
          if ( lines.length > 4)
              lines.pop();
          lines.unshift(err+'\n');
          this.setState('last_error', lines.toString());
      } catch(e) { this.logError( 'setLastError: '+e.message ); } }
      
      
      /** Auswertung der empfangenen Daten
       **/
      parseResponse (jdata, jmsg, cmd_group, cmd) { try {
          switch (cmd_group) {
              case 'event':
                  switch (cmd) {
                      case 'player_playback_error' :
                          this.setLastError(jmsg.error.replace(/_/g,' '));
                          break;
                      case 'player_state_changed' :
                          this.setState("play_state", jmsg.state);
                          break;
                      case 'player_volume_changed' :
                          this.setState("volume", jmsg.level );
                          this.setState("mute", (jmsg.mute=='on' ? true : false) );
                          break;
                      case 'player_repeat_mode_changed' :
                          this.setState("play_mode_shuffle", jmsg.shuffle );
                          break;
                      case 'player_shuffle_mode_changed' :
                          this.setState("play_mode_repeat", jmsg.repeat );
                          break;
                      case 'player_now_playing_changed' :
                          this.sendCommand('get_now_playing_media');
                          break;
                      case 'player_now_playing_progress' :
                          this.setState("cur_pos", jmsg.cur_pos / 1000);
                          this.setState("cur_pos_MMSS", this.toMMSS(jmsg.cur_pos / 1000));
                          this.setState("duration", jmsg.duration / 1000);
                          this.setState("duration_MMSS", this.toMMSS(jmsg.duration / 1000));
                          break;
                  }        
                  break;
                  
                  
              case 'player':
                  switch (cmd) {
                      case 'set_volume' :
                      case 'get_volume' :
                          if ( getState(this.statePath+"volume").val != jmsg.level)
                              this.setState("volume", jmsg.level);
                          break;
                      case 'set_mute' :
                      case 'get_mute' :
                          this.setState("mute", (jmsg.state=='on' ? true : false) );
                          break;
                      case 'set_play_state' :
                      case 'get_play_state' :
                          this.setState("play_state", jmsg.state);
                          break;
                      case 'set_play_mode' :
                      case 'get_play_mode' :
                          this.setState("play_mode_repeat", jmsg.repeat);
                          this.setState("play_mode_shuffle", (jmsg.shuffle=='on'?true:false) );
                          break;
                      case 'get_now_playing_media' :
                          this.setState("now_playing_media_type", jdata.payload.type);
                          if (jdata.payload.hasOwnProperty('song'))
                              this.setState("now_playing_media_song", jdata.payload.song);
                          if (jdata.payload.hasOwnProperty('album'))
                              this.setState("now_playing_media_album", jdata.payload.album);
                          if (jdata.payload.hasOwnProperty('album_id'))
                              this.setState("now_playing_media_album_id", jdata.payload.album_id);
                          if (jdata.payload.hasOwnProperty('artist'))
                              this.setState("now_playing_media_artist", jdata.payload.artist);
                          if (jdata.payload.hasOwnProperty('image_url'))
                              this.setState("now_playing_media_image_url", jdata.payload.image_url);
                          if (jdata.payload.hasOwnProperty('mid'))
                              this.setState("now_playing_media_mid", jdata.payload.mid);
                          if (jdata.payload.hasOwnProperty('qid'))
                              this.setState("now_playing_media_qid", jdata.payload.qid);
                          if (jdata.payload.hasOwnProperty('station')) {
                              if (jdata.payload.type=='station') {
                                  this.setState("now_playing_media_station", jdata.payload.station);
                              } else {
                                  this.setState("now_playing_media_station", null);
                              }
                          }  
                          break;
                  }
                  break;
          } // switch
      
      
      } catch(err) { this.logError( 'parseResponse: '+err.message ); } }
       
      /** cmd der Form "cmd&param"  werden zur msg heos+cmd+pid+&param aufbereitet
          cmd der Form "cmd?param"  werden zur msg heos+cmd+?param aufbereitet
       **/
      commandToMsg (cmd) {
          var param = cmd.split('&');
          cmd = param[0];
          if ( param.length > 1 ) param='&'+param[1]; else param=''; 
          var cmd_group = 'player';
      
          switch (cmd) {
              case 'get_play_state':
              case 'get_play_mode':
              case 'get_now_playing_media':
              case 'get_volume':
              case 'play_next':
              case 'play_previous':
              case 'set_mute':       // &state=on|off        
              case 'set_volume':     // &level=1..100   
              case 'volume_down':    // &step=1..10   
              case 'volume_up':      // &step=1..10
              case 'set_play_state': // &state=play|pause|stop
              case 'set_play_mode':  // &repeat=on_all|on_one|off  shuffle=on|off
                  break;
      
              // browse            
              case 'play_preset':    // heos://browse/play_preset?pid=player_id&preset=preset_position
                  cmd_group = 'browse';
                  break;
              case 'play_stream':    // heos://browse/play_stream?pid=player_id&url=url_path
                  cmd_group = 'browse';
                  break;
                  
          }        
          return 'heos://'+cmd_group+'/'+cmd+'?pid=' + this.pid + param;
      }
      
      /** Nachricht (command) an player senden
          es sind auch mehrere commands, getrennt mit | erlaubt
          bsp: set_volume&level=20|play_preset&preset=1
       **/
      sendCommand (command) {
          if ( !this.installed ) return;
      
          var cmds = command.split('|');
          for (var c=0; c<cmds.length; c++) {
              this.heos.msgs.push( this.commandToMsg(cmds[c]) );
          }
          this.heos.sendNextMsg();
      }
      
      
      } // end of HeosPlayer
      
      
      /* -----
         Heos
         ----- */
      // Heos Instanz erzeugen und verbinden   
      var heos = new Heos( );
      heos.connect();
      
      // wenn das Script beendet wird, dann auch die Heos Instanz beenden
      onStop(function () { 
          heos.disconnect(); 
      }, 0 );
      
      UhulaU 1 Antwort Letzte Antwort
      0
      • W withstu

        @Uhula Irgendwie funktioniert der keep alive Mechanismus vom net socket nicht korrekt. Auch wenn ich das Device ausgeschaltet habe, wurde das Timeout Event nicht geworfen. Habe jetzt den HEOS Heartbeat zusätzlich implementiert. Sollte der Master mal ausgeschaltet werden und der Heartbeat Timeout 60 Sekunden keine Reaktion von dem Device bekommen, wird nun ein reconnect bzw. eine Suche nach einem neuen Master durchgeführt. Zusätzlich wird die ssdp Suche jetzt so oft wiederholt, bis ein Device gefunden wurde.

        /****************************
        ### HEOS Script for ioBroker
        
        #### Funktion
        
        Das Script stellt zwei JS Klassen zur Steuerung der Denon HEOS Geräte zur Verfügung. Die class Heos dient dabei dem Erkennen und Steuern der HEOS Geräte. Die class HeosPlayer dient der Interpretation der Antworten der Heos Geräte.
         
        Das Script muss lediglich gestartet werden, es sucht dann im Netzwerk nach HEOS Playern und erzeugt in der aktuellen Javascript-Instanz einen Subeintrag für die Favoriten und je einen Subeintrag für jeden gefundenen Player. Dort wiederum werden State-Variablen zur Aufnahme der Player-Daten angelegt.
         
        Das Script erzeugt auch on-Handler um auf Steuerungen über vis und andere Scripte an den State-Variablen reagieren zu können.
         
        Beim Beenden des Scripts werden alle Verbindungen und on-Handler geschlossen.
        
        Das Script ermöglicht die HEOS Player zu steuern, es soll aber nicht die HEOS App ersetzen. 
         
          
        #### Wichtig!
        
        * Im Javascript-Adapter muss in der Instanz-Konfiguration "node-ssdp" mit angegeben werden! Alternativ kann die Bibliothek auch komplett über "npm install node-ssdp" installiert werden.
        * Wenn mit Favoriten (Presets) gearbeitet werden soll, müssen die HEOS-Konto Logindaten in den beiden Konstanten HEOS_USERNAME (EmailAdr) und HEOS_PASSWORD hier im Script in der Konfiguration angegeben werden (so, wie in der HEOS App)!
        * Eine Konfiguration von IP-Adressen und Player-IDs ist nicht notwendig!
        * U.U. kann es notwendig sein das Script nach dem 1.Start zu beenden und nach 30 Sek erneut zu starten, da die Neuanlage der ioBroker States etwas Zeit benötigt. Warnungen sind dabei zu ignorieren. ;-)
        
        #### Updates
         
        ##### v2.0 13.03.2020
        * das Script überprüft nun, ob alle notwendigen states für Heos und HeosPlayer im ioBroker korrekt erzeugt wurden und gibt eine Warnung mit Script-Neustartaufforderung aus, wenn die states nicht vorhanden sind. Dieses ist notwendig, da das Anlegen von states asynchron erfolgt und einige ms dauern kann
        * (WICHTIG!) die states werden nicht mehr in der aktuellen Javascript-Instanz und auch nicht mehr unter der IP des Heos-Players gespeichert, sondern Javascript-Instanzunabhängig unter 0_userdata.0 und seiner Player-ID (pid), da diese sich nicht ändert. Die IP hingegen u.U. schon. Also statt "javascript.X.heos.192_168_2_43" nun als "0_userdata.0.heos.12345678". Wer bereits auf die alten Werte im VIS zugreift, muss dieses im VIS anpassen!  
        * es wurden Befehle/states für die Gruppensteuerung der Heos-Player hinzugefügt. Beim Start werden die Gruppen ausgelesen und in den Player-states des Gruppenleiters (der erste genannte Player) gespeichert. Über dessen states kann die Gruppe gesteuert werden: 
            group_volume: dient der Steuerung der Gruppen-Lautstärke
            group_mute: dient der Steuerung der Gruppen-Mutes
            group_leader: ist true, wenn der Player der Gruppenleiter ist
            group_member: ist true, wenn der Player Mitglied einer Gruppe ist
        * alle 60 Sek wird überprüft, ob noch alle HEOS-Player erreichbar sind bzw. neue/reconnectete hinzugekommen sind. Neue/reconnectete werden der Liste der HEOS-Player hinzugefügt, fehlende werden gestoppt. Da hierzu das HEOS-Netzwerk gefragt wird (get_players Meldung), kann es bis zu 5 Min dauern bis Änderungen erkannt werden. Der neue HEOS-Player-State "connected" wird entsprechend gesetzt
        * jeder HEOS-Player hat einen neuen state "connected", dieser wird nach erfolgreichem Start auf true gesetzt, bei korrektem Beenden des Scripts auf false
        * diverse Filter/Korrekturen aus dem Forum übernommen, vielen dank an withstu
          
          
         #### class Heos
         
         Diese Basisklasse dient 
        
        * dem Erkennen von HEOS Geräten (Playern). Das Erkennen der HEOS Geräte findet via UPD unter Nutzung von node-ssdp statt. node-ssdp muss dazu im Javascript-Adapter in der Konfiguration mit angegeben werden!
        * der Kommunikation über TelNet. Es wird genau eine TelNet Verbindung zu einem HEOS Gerät aufgebaut, dieses reicht die Sendungen und Antworten zentral weiter
        * der Ermittlung von Favoriten (Presets). Für jeden Favorit wird ein ioBroker State heos.presets.n mit entsprechenden Sub-States erzeugt. Zur Nutzung der Presets ist ein SignIn notwendig, hierzu müssen HEOS_USERNAME und HEOS_PASSWORD gesetzt werden.
        * dem Instanziieren der class HeosPlayer je HEOS Gerät. Je HEOS Gerät wird ein ioBroker-State mit der IP-Adresse des Players erzeugt, dieser State erhält diverse Sub-States
          
        ##### State-Variable: Heos
         
        Werden angelegt unter "0_userdata.0.heos."
        
        * connected: true wenn die Verbindung zu mindestens einem HEOS-Player besteht
        * script_version: Version des Scripts, dient dazu Script-Updates zu erkennen
        * last_error: Letzter Fehlertext
        * command(cmd): Hierüber können der Heos-Klasse Befehle übergeben werden, für cmd gilt:
            "connect": Verbindung zu HEOS aufbauen bzw. erneut aufbauen (praktisch ein reset)
            "disconnect": Verbindung zu HEOS beenden
            "load_presets": lädt die Favoriten neu
          
            "group/set_group?pid=<pid1>,<pid2>,...": setzen einer Gruppe, die pids sind die der Player wie sie unter den Objekten für jeden Player abgelegt sind. Bsp: "group/set_group?pid=12345678,12345679". 
         
           "group/set_group?pid=<pid1>" : hebt die Gruppierung des Players mit der pid1 wieder auf. Bsp: "group/set_group?pid=12345678"
           "...": alle anderen cmd-Werte werden "as is" versucht an HEOS zu senden
         
          
        * presets.<n>: Hierunter werden die Favoriten, Presets angelegt. Je Favorit ein Unterordner n=1 bis Anzahl. Darunter befinden sich dann die States, welche den Inhalt der Favoriten aufnehmen:
         
        * image_url (read): Bild des Favoriten 
        * name (read): Name des Favoriten
        * playable (read): Spielbar? true/false
        * type (read): Typ des Favoriten (station, ...)
         
            
           
         #### class HeosPlayer 
         
         Diese Klasse dient
        * der Steuerung genau eines HEOS Gerätes. Hierzu wird die zentrale Telnet Verbindung der class Heos genutzt.
        * dem Erzeugen der ioBroker-States zum Speichern der Geräte-Werte
        * der Auswertung von Antworten der HEOS Geräte und Zuweisung an die entsprechenden ioBroker-States
         
        ##### State-Variable
        
        Werden angelegt unter "0_userdata.0.heos.<pid>"
        
        * connected : true, wenn eine Verbindung besteht, sonst false
        * command(cmd): Hierüber können dem Heos-Player Befehle übergeben werden. Diese werden im Klartext in die State-Variable geschrieben. Getrennt durch das | Zeichen können mehrere hintereinander eingetragen werden. Bsp: Setzen der Lautstärke auf 20 und Abspielen des 1.Favoriten "set_volume&level=20|play_preset&preset=1|set_play_state&state=play". Folgende cmd sind erlaubt:
        
          "set_volume&level=0|1|..|100" : Setzt die gewünschte Lautstärke 
          "set_play_state&state=play|pause|stop" : Startet und stoppt die Wiedergabe
          "set_play_mode&repeat=on_all|on_one|off&shuffle=on|off": Setzt Wiederholung und Zufallsweidergabe
          "set_mute&state=on|off" : Stumm schalten oder nicht
          "volume_down&step=1..10" : Lautstärke verringern um   
          "volume_up&step=1..10"  : Lauststäre erhöhen um
          "play_next"  : Nächsten Titel spielen
          "play_previous" : Vorherigen Titel spielen
          "play_preset&preset=1|2|..|n" : Favorit Nr n abspielen
          "play_stream&url=url_path" : URL-Stream abspielen
         
        * cur_pos (read) : lfd. Position der Wiedergabe in [Sek]
        * cur_pos_MMSS (read) : lfd. Position der Wiedergabe im Format MM:SS
        * duration (read) : Länge des aktuellen Titels in [Sek]
        * duration_MMSS (read) : Länge des aktuellen Titels im Format MM:SS
        * ip (read): IP-Adresse des HEOS Players
        * last_error (read): Text des letzten Fehlers, der vom Player gesendet wurde. Wird bei jedem neuen Befehl zurückgesetzt. Wenn man bspw. versucht eine Wiedergabe über Amazon o.ä. zu starten und es gibt aber keine Verbindung dahin, steht hier der Fehlertext drin
        * model (read): Modell des HEOS Players
        * mute (read write): Boolsche Variable, die anzeigt ob der Player gemutet (Stumm geschaltet) wurde. Hierüber kann auch ein mute gesetzt werden
        * name (read): Name des HEOS Players
        * now_playing_media_... (read) : Eine Gruppe von States, in welchen Infos über den aktuellen Titel gespeichert werden, wird automatisch aktualisiert. 
        * pid (read): Player-ID des HEOS Players
        * play_mode_repeat (read write) : Repeat-Modus der Wiedergabe. Mögliche Werte: on_all|on_one|off  
        * play_mode_shuffle (read write) : Zufallswiedergabe true/false
        * play_state (read write): Zustand des Players. Mögliche Werte play|pause|stop
        * serial (read): Seriennummmer des HEOS Players
        * volume (read write): Lautstärke im Bereich 0 - 100. 
        * group_leader : Ist Gruppenleiter
        * group_member : Ist Gruppenmitglied
        * group_pid : Player pids in der Gruppe
        * group_volume : Lautstärke wenn Gruppen-Leiter
        * group_name : Name der Gruppe
        * group_mute : Gruppe gemutet?
        
         
        #### Weiterführende Links
        
        * HEOS CLI Protokoll: http://rn.dmglobal.com/euheos/HEOS_CLI_ProtocolSpecification.pdf
        * http://forum.iobroker.net/viewtopic.php?f=30&t=5693&p=115554#p115554
         
         
        (c) Uhula, MIT License, no warranty, use on your own risc
         
        */
        
        /****************************
         * Konfiguration
         ****************************/
         
        const HEOS_USERNAME = '';
        const HEOS_PASSWORD = '';
        
        
        /****************************
         * ab hier nichts mehr ändern ;-) 
         ****************************/
        
        var net = require('net');
        
        const stateDISCONNECTED = 0;
        const stateSEARCHING = 1;
        const stateCONNECTING = 2;
        const stateCONNECTED = 3;
        const SCRIPTVERSION = '2.0/2020-03-13';
        
        /********************
         * class Heos
         ********************/
        class Heos  {
        
        logDebug(msg) { console.debug('[Heos] '+msg); }
        log(msg) { console.log('[Heos] '+msg); }
        logWarn(msg) { console.warn('[Heos] '+msg); }
        logError(msg) { console.error('[Heos] '+msg); }
        
        constructor() {
            this.init();
            this.states = [
                { id:"command",        common:{name:"Kommando für HEOS Aufrufe"}                   },
                { id:"connected",      common:{name:"Verbunden?",                     write:false, def:false } },
                { id:"last_error",     common:{name:"Letzte Fehler",                  write:false} },
                { id:"script_version", common:{name:"Installierte Script-Version", write:false } }
            ];
            // beim 1.Start nur die States erzeugen
            if ( !this.existState("script_version") || (this.getState('script_version').val!=SCRIPTVERSION) ) {
                this.installed = false;
                this.logWarn('creating HEOS states for version '+SCRIPTVERSION+', please start script again');
                // Anlage der States 
                for (var s=0; s<this.states.length; s++) {
                    this.setState( this.states[s].id );
                }
                this.setState('script_version', SCRIPTVERSION);
            }
            else {   
                this.installed = true;
                on({id: this.statePath+'command', change: "any"}, (obj) => {
                        this.executeCommand( obj.state.val );
                    });
            }
        }
        
        
        
        // Initialisierung
        init() {
            this.statePath = '0_userdata.0.heos.';
            this.players = [];
            this.heartbeatInterval = undefined;
            this.heartbeatTimeout = undefined;
            this.ssdpSearchInterval = undefined;
            this.getPlayersInterval = undefined;
            this.net_client = undefined;
            this.nodessdp_client = undefined;
        
            this.ip='';
            this.msgs = [];
            this.lastResponse = '';
            this.state = stateDISCONNECTED;
            this.unfinishedResponses = '';
            this.ssdpSearchTargetName = 'urn:schemas-denon-com:device:ACT-Denon:1';
        }
        
        
        // über den $-Operator nachsehen, ob der state bereits vorhanden ist
        // getState().notExists geht auch, erzeugt aber Warnmeldungen!
        existState(id) {
            return ( $(this.statePath+id).length==0?false:true);
        }
        
        // wrapper
        getState(id) {
            return getState(this.statePath + id);
        }
        
        // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
        // wenn er noch nicht da ist
        setState(id,value) {
            if ( !this.existState(id) ) this.createState(id, value, undefined);
            else setState( this.statePath + id, value);
        }
        
        // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
        // vorhanden sind (wenn der common-Parameter leer ist)
        createState(id, value, common) {
            if ( !this.existState(id) ) {
                if (common===undefined) {
                    // id im states-Array suchen
                    for (var i=0; i<this.states.length; i++) { 
                        if (this.states[i].id==id) {
                            if (this.states[i].hasOwnProperty('common'))
                                common = this.states[i].common;
                           break;
                        }   
                    }
                }
                if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                // unter "0_userdata.0"
                let obj = {};
                obj.type = 'state';
                obj.native = {};
                obj.common = common;
                setObject(this.statePath + id, obj, (err) => {
                        if (err) {
                            this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                        } else { 
                            this.log('state "' + this.statePath + id + '" created');
                        }
                });
              
                // value zeitversetzt setzen        
                setTimeout( setState, 3000, this.statePath + id, value );
            }
        }
        
        /** Verbindung zum HEOS System herstellen
         **/
        connect() { 
            if ( !this.installed ) return;
        
            try {
                this.log("searching for HEOS devices ...")
                this.setState( "connected", false );
                this.state = stateSEARCHING;
                const NodeSSDP = require('node-ssdp').Client;
        	    this.nodessdp_client = new NodeSSDP();
        	    this.nodessdp_client.explicitSocketBind = true;
        	    this.nodessdp_client.on('response', (headers, statusCode, rinfo) => this.onNodeSSDPResponse(headers, statusCode, rinfo) );
                this.nodessdp_client.on('error', error => {	this.nodessdp_client.close(); this.logError(error); });
                this.nodessdp_client.search(this.ssdpSearchTargetName);
                this.ssdpSearchInterval = setInterval(() => {
                    this.log("still searching for HEOS devices ...")
                    this.nodessdp_client.search(this.ssdpSearchTargetName);
                }, 30000);
            } catch(err) { this.logError( 'connect: '+err.message ); } 
            
        }
        
        
        /** Alle Player stoppen und die TelNet Verbindung schließen 
         **/
        disconnect() {
            this.log('disconnecting from HEOS ...');
            unsubscribe(this.statePath.substr(0,this.statePath.length-1));
        
            this.stopHeartbeat();
            this.stopPlayers();
        
            if (typeof this.net_client!=='undefined') {
                this.registerChangeEvents( false );
                this.net_client.destroy();
                this.net_client.unref();
            }
            if (typeof this.nodessdp_client!=='undefined') {
                this.nodessdp_client.stop();
            }
            this.setState( "connected", false );
            this.log('disconnected from HEOS');
        }
        
        reconnect(){
            this.log('reconnecting to HEOS ...');
            this.disconnect();
            this.init();
            this.connect();
        }
        
        executeCommand(cmd) {
        //l('command: '+cmd);
            switch (cmd) {
                case 'load_presets' :
                    this.getMusicSources();
                    break;
                case 'group/get_groups' :
                    this.getGroups();
                    break;
                case 'connect' :
                    this.disconnect();
                    this.init();
                    this.connect();
                    break;
                case 'disconnect' :
                    this.disconnect();
                    break;
                default:
                    if (this.state == stateCONNECTED) {
                        this.msgs.push( 'heos://'+cmd+'\n' );
                        this.sendNextMsg();
                    }
            
            }
        }
        /** es wurde mindestens ein Player erkannt, nun über dessen IP alle bekannten HEOS Player
         *  durch senden von "player/get_players" ermitteln
         */
        onNodeSSDPResponse(headers, statusCode, rinfo) { try {
            // rinfo {"address":"192.168.2.225","family":"IPv4","port":53871,"size":430}
            if (typeof this.net_client=='undefined') {
                if(headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                    this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
                } else {
                    if (this.ssdpSearchInterval!==undefined) {
                        clearInterval(this.ssdpSearchInterval);
                        this.ssdpSearchInterval = undefined;
                    }
        
                    this.ip = rinfo.address;
                    this.log('connecting to HEOS ('+this.ip+') ...');
                    this.net_client = net.connect({host:this.ip, port:1255});
                    this.net_client.setKeepAlive(true, 5000);
                    this.net_client.setNoDelay(true);
                    this.net_client.setTimeout(15000);
        
                    this.state = stateCONNECTING;
        
                    this.net_client.on('error',(error) => {
                        this.logError(error);
                        this.reconnect();
                    }); 
            
                    this.net_client.on('connect',  () => {
                        this.setState( "connected", true );
                        this.state = stateCONNECTED;
                        this.log('connected to HEOS ('+this.ip+')');
                        this.getPlayers();
                        this.registerChangeEvents( true );
                        this.signIn();
                        this.getMusicSources();
                        this.getGroups();
                        this.startHeartbeat();
                    });
                
                    // Gegenseite hat die Verbindung geschlossen 
                    this.net_client.on('end',  () => {              
                        this.logWarn('HEOS closed the connection to '+this.ip);
                        this.state = stateDISCONNECTED;
                        this.reconnect();
                    });
        
                    // timeout
                    this.net_client.on('timeout',  () => {              
                        this.logWarn('Timeout trying connect to '+this.ip);
                        this.state = stateDISCONNECTED;
                        this.reconnect();
                    });
        
                    // Datenempfang
                    this.net_client.on('data', (data) => this.onData(data)  );
                }
            }
        } catch(err) { this.logError( 'onNodeSSDPResponse: '+err.message ); } }
        
        setLastError(err) {
            this.logWarn(err);
            /*
            var val = getState(this.statePath+'last_error').val;
            var lines = val.splitt('\n');
            if ( lines.length > 4)
                lines.pop();
            lines.unshift(err+'\n');
        l(lines);       
            this.setState('last_error', lines.toString());
            */    
        }
        
        
        /** es liegen Antwort(en) vor
         * 
         * {"heos": {"command": "browse/browse", "result": "success", "message": "sid=1028&returned=9&count=9"}, 
         *    "payload": [
         *        {"container": "no", "mid": "s25529", "type": "station", "playable": "yes", "name": "NDR 1 Niedersachsen (Adult Hits)", "image_url": "http://cdn-profiles.tunein.com/s25529/images/logoq.png?t=154228"}, 
         *        {"container": "no", "mid": "s56857", "type": "station", "playable": "yes", "name": "NDR 2 Niedersachsen 96.2 (Top 40 %26 Pop Music)", "image_url": "http://cdn-profiles.tunein.com/s56857/images/logoq.png?t=154228"}, 
         *        {"container": "no", "mid": "s24885", "type": "station", "playable": "yes", "name": "NDR Info", "image_url": "http://cdn-profiles.tunein.com/s24885/images/logoq.png?t=1"}, {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
         *        {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}, 
         *        {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
         *        {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk"
         **/
        onData(data) {  try {
            data = data.toString();
            data=data.replace(/[\n\r]/g, '');    // Steuerzeichen "CR" entfernen   
            // es können auch mehrere Antworten vorhanden sein! {"heos": ... } {"heos": ... }
            // diese nun in einzelne Antworten zerlegen
            data = this.unfinishedResponses + data;
            this.unfinishedResponses = '';
            
            data=data.replace(/{"heos":/g, '|{"heos":');    
            var responses = data.split('|');
            responses.shift();
            for (var r=0; r<responses.length; r++ ) if(responses[r].trim().length > 0) {
                try {
                    JSON.parse(responses[r]); // check ob korrektes JSON Array
                    this.parseResponse(responses[r]);
                } catch(e) {
                    this.logDebug('onData: invalid json (error: ' + e.message + '): ' + responses[r]);
                    this.unfinishedResponses += responses[r];
                }
            }
            // wenn weitere Msg zum Senden vorhanden sind, die nächste senden
            if (this.msgs.length>0)
                this.sendNextMsg();
        } catch(err) { this.logError( 'onData: '+err.message ); } }
        
        /** Antwort(en) verarbeiten. Sich wiederholende Antworten ignorieren
         **/
        parseResponse (response) { try {
            if (response == this.lastResponse || response.indexOf("command under process") > 0 )
                return
            this.lastResponse = response;        
            
            var jmsg;
            var i;
            var jdata = JSON.parse(response);
            if ( !jdata.hasOwnProperty('heos') || !jdata.heos.hasOwnProperty('command') || !jdata.heos.hasOwnProperty('message') ) 
                return;
        
            // msg auswerten
            try {
                jmsg = '{"' + decodeURI(jdata.heos.message).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"').replace(/\s/g,'_') + '"}';
                jmsg = JSON.parse(jmsg);
            } catch(err) {
                jmsg = {};
            }
        
            this.logDebug('parseResponse: '+response); 
        
            // result ?
            var result = 'success';
            if (jdata.heos.hasOwnProperty('result') ) result = jdata.heos.result;
            if ( result!='success' ) { 
                this.setLastError('result='+result+', '+jmsg.text);
            }
        
            // cmd auswerten
            var cmd = jdata.heos.command.split('/');
            var cmd_group = cmd[0];
            cmd = cmd[1];
            switch (cmd_group) {
                case 'system':
                    switch(cmd) {
                        case 'heart_beat':
                            this.resetHeartbeatTimeout();
                            break;
                    }
                    break;
                case 'event':
                    switch (cmd) {
                        case 'group_volume_changed' :
                        // "heos": {"command": "event/group_volume_changed ","message": "gid='group_id'&level='vol_level'&mute='on_or_off'"}
                        this.getGroups();
                        break;
                    }
                    break;
                case 'player':
                    switch (cmd) {
                            // {"heos": {"command": "player/get_players", "result": "success", "message": ""}, 
                            //  "payload": [{"name": "HEOS Bar", "pid": 1262037998, "model": "HEOS Bar", "version": "1.430.160", "ip": "192.168.2.225", "network": "wifi", "lineout": 0, "serial": "ADAG9170202780"}, 
                            //              {"name": "HEOS 1 rechts", "pid": -1746612370, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.201", "network": "wifi", "lineout": 0, "serial": "AMWG9170934429"}, 
                            //              {"name": "HEOS 1 links", "pid": 68572158, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.219", "network": "wifi", "lineout": 0, "serial": "AMWG9170934433"}
                            //             ]}
                        case 'get_players' :
                            if (jdata.hasOwnProperty('payload')) {
                                if (jdata.payload.length != this.players.length) {
                                    this.stopPlayers();
                                    this.players = [];
                                    for (i=0; i<jdata.payload.length; i++) {
                                        var player = jdata.payload[i];
                                        this.players.push(player);
                                    }
                                    this.startPlayers();
                                } 
                            }
                            break;
                    }
                    break;
        
                // {"heos": {"command": "browse/get_music_sources", "result": "success", "message": ""}, 
                //  "payload": [{"name": "Amazon", "image_url": "https://production...png", "type": "music_service", "sid": 13}, 
                //              {"name": "TuneIn", "image_url": "https://production...png", "type": "music_service", "sid": 3}, 
                //              {"name": "Local Music", "image_url": "https://production...png", "type": "heos_server", "sid": 1024}, 
                //              {"name": "Playlists", "image_url": "https://production...png", "type": "heos_service", "sid": 1025}, 
                //              {"name": "History", "image_url": "https://production...png", "type": "heos_service", "sid": 1026}, 
                //              {"name": "AUX Input", "image_url": "https://production...png", "type": "heos_service", "sid": 1027}, 
                //              {"name": "Favorites", "image_url": "https://production...png", "type": "heos_service", "sid": 1028}]}
                case 'browse':
                    switch (cmd) {
                        case 'get_music_sources' :
                            if ( (jdata.hasOwnProperty('payload')) ) {
                                for (i=0; i<jdata.payload.length; i++) {
                                    var source = jdata.payload[i];
                                    if (source.name=='Favorites') {
                                        this.browse(source.sid);
                                    }
                                }
                            }
        
                            break;
                            
        	    // {"heos": {"command": "browse/browse", "result": "success", "message": "pid=1262037998&sid=1028&returned=5&count=5"}, 
        	    //  "payload": [{"container": "no", "mid": "s17492", "type": "station", "playable": "yes", "name": "NDR 2 (Adult Contemporary Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s17492q.png"}, 
        	    //              {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
        	    //              {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk", "type": "station", "playable": "yes", "name": "Ed Sheeran", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/EdSheeran._SX200_SY200_.jpg"}, 
        	    //              {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
        	    //              {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}], 
        	    //  "options": [{"browse": [{"id": 20, "name": "Remove from HEOS Favorites"}]}]}                    
                        case 'browse' :
                            if ( (jdata.hasOwnProperty('payload')) ) {
                                for (i=0; i<jdata.payload.length; i++) {
                                    var preset = jdata.payload[i];
                                    this.createState( 'presets.'+(i+1)+'.name', preset.name, {name: 'Favoritenname ' });
                                    this.createState( 'presets.'+(i+1)+'.playable', (preset.playable=='yes'?true:false), {name: 'Favorit ist spielbar' });
                                    this.createState( 'presets.'+(i+1)+'.type', preset.type, {name: 'Favorittyp' });
                                    this.createState( 'presets.'+(i+1)+'.image_url', preset.image_url, {name: 'Favoritbild' });
                                }
                            }
                            break;
                    }     
                    break;
        
                case 'group':
        //l('group: '+response);
                    switch (cmd) {
                          // { "heos":{"command":"player/set_group","result":"success",
                          //           "message": "gid='new group_id'&name='group_name'&pid='player_id_1, player_id_2,…,player_id_n'
                          //          } 
                          // }
                        case 'set_group' :
                            this.setGroup( jmsg );
                            break;
        
                        // { "heos": {"command":"group/get_volume","result":"success","message": "gid='group_id'&level='vol_level'"}
                        case 'get_volume':
                            if ( jmsg.hasOwnProperty('gid') ) {
                                if ( jmsg.hasOwnProperty('level') ) {
                                    this.setState( jmsg.gid+'.group_volume', jmsg.level);
                                }
                            }
                            break;
        
                        // { "heos": {"command":"group/get_mute","result":"success","message": "gid='group_id'&state='on_or_off'"}
                        case 'get_mute':
                            if ( jmsg.hasOwnProperty('gid') ) {
                                if ( jmsg.hasOwnProperty('state') ) {
                                    this.setState( jmsg.gid+'.group_mute', (jmsg.state=='on' ? true : false));
                                }
                            }
                            break;
        
        
                        // { "heos": { "command": "player/get_groups", "result": "success", "message": "" },
                        //   "payload": [{"name":"'group name 1'", "gid": "group id 1'",
                        //                "players":[{"name":"player name 1","pid":"'player id1'","role":"player role 1 (leader or member)'"},
                        //                           {"name":"player name 2","pid":"'player id2'","role":"player role 2 (leader or member)'"} 
                        //                          ]
                        //               },
                        //               {"name":"'group name 2'","gid":"group id 2'",
                        //                "players":[{"name":"player name ... 
                        case 'get_groups' :
                            // bisherige groups leeren
                            var objs = $(this.statePath+'*.group_name');
                            for (var o=0; o<objs.length; o++) setState(objs[o], 'no group');
                            objs = $(this.statePath+'*.group_leader');
                            for (var o=0; o<objs.length; o++) setState(objs[o], false);
                            objs = $(this.statePath+'*.group_member');
                            for (var o=0; o<objs.length; o++) setState(objs[o], false);
                            objs = $(this.statePath+'*.group_pid');
                            for (var o=0; o<objs.length; o++) setState(objs[o], '');
        
                            // payload mit den groups auswerten
                            if ( (jdata.hasOwnProperty('payload')) ) {
                                for (i=0; i<jdata.payload.length; i++) {
                                    var group = jdata.payload[i];
                                    var players = group.players;
                                    // Player IDs addieren. Hinweis: "leader" ist nicht immer der 1.Playereintrag
                                    group.pid = "";
                                    for (var p=0; p<players.length; p++) {
                                        if ( players[p].role == 'leader' )
                                            group.pid = players[p].pid + (group.pid.length>0?",":"") + group.pid;
                                        else
                                            group.pid = group.pid + (group.pid.length>0?",":"") + players[p].pid;
                                    }
                                    this.setGroup(group);
                                }
                            }
                            break;
                            
                    }     
                    break;
        
        
                case 'system':
                    switch (cmd) {
                        case 'sign_in' :
                            this.log('signed in: '+jdata.heos.result);
                            break;
                    }     
                    break;
            }
        
        
            // an die zugehörigen Player weiterleiten
            if ( jmsg.hasOwnProperty('pid') ) {
                for (i=0; i<this.players.length; i++)
                    if (jmsg.pid==this.players[i].heosPlayer.pid) {
                        this.players[i].heosPlayer.parseResponse (jdata, jmsg, cmd_group, cmd);
                        break;
                    }
            }
        
            
        } catch(err) { this.logError( 'parseResponse: '+err.message+'\n '+response ); } }
        
        
        // sucht die zur pid passenden player-Insanz
        sendCommandToPlayer(objID, cmd ) {
           // aus der objID die pid holen
           // objID = javascript.1.heos.394645376.command
           objID = objID.split('.');
           var pid = objID[3];
           for (var p=0; p<this.players.length; p++ ) 
               if (this.players[p].pid == pid ) {
                   this.players[p].heosPlayer.sendCommand( cmd );
                   break;
               }
        } 
        
        // Für die gefundenen HEOS Player entsprechende class HeosPlayer Instanzen bilden 
        startPlayers() { try {
           this.stopPlayers();
            let i=0;
            for (i=0; i<this.players.length; i++) {
               this.players[i].heosPlayer = new HeosPlayer( this, this.players[i]  );
            }
        
            // alle 30 Sekunden auf neue Player untersuchen
            this.getPlayersInterval = setInterval(() => {
                this.getPlayers();
            }, 30000);
        
        /*
            // Events setzen
            for (i=0; i<this.players.length; i++) {
                let heosPlayer = this.players[i].heosPlayer;
                heosPlayer.onHandler = [];
                // on-Event für command
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'command', change: "any"}, (obj) => {
                    this.sendCommandToPlayer( obj.id, obj.state.val ) 
                }));
        
                // on-Event für volume (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'volume', change:'ne', ack:false }, (obj) => {
                    this.sendCommandToPlayer( obj.id, 'set_volume&level='+obj.state.val );
                }));
                // on-Event für mute (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'mute', change: 'ne', ack:false}, (obj) => {
                    this.sendCommandToPlayer( obj.id, 'set_mute&state='+ (obj.state.val === true ? 'on' : 'off') );
                }));
                // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'play_mode_shuffle', change: 'ne', ack:false}, (obj) => {
                    this.sendCommandToPlayer( obj.id, 'set_play_mode&shuffle='+ (obj.state.val === true ? 'on' : 'off') );
                }));
                // on-Event für play_state (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'play_state', change: 'ne', ack:false}, (obj) => {
                    this.sendCommandToPlayer( obj.id, 'set_play_state&state='+ obj.state.val );
                }));
        
                // on-Event für group-volume (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'group_volume', change:'ne', ack:false }, (obj) => {
                    // "id":"javascript.1.heos.-1746612370.group_volume"
                    var id = obj.id.split('.');
                    this.executeCommand( 'group/set_volume?gid='+id[3]+'&level='+obj.state.val );
                }));
        
                // on-Event für group-mute (nur wenn ack=false, also über vis)
                heosPlayer.onHandler.push( on({id: heosPlayer.statePath+'group_mute', change:'ne', ack:false }, (obj) => {
                    // "id":"javascript.1.heos.-1746612370.group_volume"
                    var id = obj.id.split('.');
                    this.executeCommand( 'group/set_mute?gid='+id[3]+'&state='+(obj.state.val===true ? 'on':'off') );
                       }));
            }    
        */
        } catch(err) { this.logError( 'startPlayers: '+err.message ); } }
        
        //
        stopPlayers() { try {
            if (this.getPlayersInterval!==undefined) {
                clearInterval(this.getPlayersInterval);
                this.getPlayersInterval = undefined;
            }
            for (let i=0; i<this.players.length; i++) {
                let heosPlayer = this.players[i].heosPlayer;
                if (heosPlayer)
                    heosPlayer.stopPlayer();
                // player leeren
                this.players[i].heosPlayer = undefined;
            }
        } catch(err) { this.logError( 'stopPlayers: '+err.message ); } }
        
        // setzen der Werte einer Group
        setGroup(group) {
            if ( group.hasOwnProperty('pid') ) {    
                // in den Playern den Groupstatus setzen
                var pids = group.pid.split(',');
                  
                for (var i=0; i<pids.length; i++) {
                    this.setState(pids[i]+'.group_name', (group.hasOwnProperty('name')?group.name:''));
                    this.setState(pids[i]+'.group_pid', group.pid);
                    this.setState(pids[i]+'.group_leader', (i==0) && (pids.length>1) );
                    this.setState(pids[i]+'.group_member', (pids.length>1));
                }
                    
                if ( group.hasOwnProperty('gid') ) {   
                    // volume und mute dazu holen
                    this.executeCommand("group/get_volume?gid="+group.gid);
                    this.executeCommand("group/get_mute?gid="+group.gid);
                }
            }
        
        }
        
        getPlayers() {
            if (this.state == stateCONNECTED) {
                this.msgs.push( 'heos://player/get_players\n' );
                this.sendNextMsg();
            }
        }
        
        registerChangeEvents( b ) {
            if (this.state == stateCONNECTED) {
                if (b) this.msgs.push( 'heos://system/register_for_change_events?enable=on' );
                else this.msgs.push( 'heos://system/register_for_change_events?enable=off' );
                this.sendNextMsg();
            }
        }
        
        signIn() {
            if (this.state == stateCONNECTED) {
                // heos://system/sign_in?un=heos_username&pw=heos_password
                this.msgs.push( 'heos://system/sign_in?un='+HEOS_USERNAME+'&pw='+HEOS_PASSWORD );
                this.sendNextMsg();
            }
        }
        
        getMusicSources() {
            if (this.state == stateCONNECTED) {
                // heos://browse/get_music_sources
                this.msgs.push( 'heos://browse/get_music_sources' );
                this.sendNextMsg();
            }
            
        }
        
        getGroups() {
            if (this.state == stateCONNECTED) {
                // heos://group/get_groups
                this.msgs.push( 'heos://group/get_groups' );
                this.sendNextMsg();
            }
            
        }
        
        startHeartbeat(){
            this.logDebug("start heartbeat interval");
            this.heartbeatInterval = setInterval(() => {
                this.logDebug("heartbeat")
                this.msgs.push( 'heos://system/heart_beat' );
                this.sendNextMsg();
                if (this.heartbeatTimeout==undefined) {
                    this.heartbeatTimeout = setTimeout(() => {
                        this.log("heartbeat timeout");
                        this.reconnect();
                    }, 60000);
                }
            }, 15000);
        }
        
        resetHeartbeatTimeout(){
            this.logDebug("reset heartbeat timeout");
            if (this.heartbeatTimeout!==undefined) {
                clearTimeout(this.heartbeatTimeout);
                this.heartbeatTimeout = undefined;
            }
        }
        
        stopHeartbeat(){
            this.logDebug("stop heartbeat interval");
            if (this.heartbeatInterval!==undefined) {
                clearInterval(this.heartbeatInterval);
                this.heartbeatInterval = undefined;
            }
            this.resetHeartbeatTimeout();
        }
        
        browse(sid) {
            if (this.state == stateCONNECTED) {
                // heos://browse/browse?sid=source_id
                this.msgs.push( 'heos://browse/browse?sid='+sid );
                this.sendNextMsg();
            }
            
        }
        
        
        sendNextMsg () {
            if (this.msgs.length>0) {
                var msg = this.msgs.shift();
                this.sendMsg(msg);
            }
        }
        
        // Nachricht an player senden
        sendMsg (msg) {
            this.net_client.write(msg + "\n");
            this.logDebug("data sent: "+ msg);
        }
        
        
        } // end of class Heos
        
        /********************
         * class HeosPlayer
         ********************/
        
        class HeosPlayer  {
        
        logDebug(msg) { console.debug('[HeosPlayer '+this.pid+'] '+msg); }
        log(msg) { console.log('[HeosPlayer '+this.pid+'] '+msg); }
        logWarn(msg) { console.warn('[HeosPlayer '+this.pid+'] '+msg); }
        logError(msg) { console.error('[HeosPlayer '+this.pid+'] '+msg); }
        
        constructor(heos, player) {
            this.heos = heos;
            this.ip = player.ip;
            this.name = player.name;
            this.pid = player.pid;
            this.model = player.model;
            this.serial = player.serial;
            this.onHandler = [];
        
        //    this.statePath = 'javascript.'+instance+'.heos.'+this.ip.replace(/\./g,'_')+".";
            this.statePath = '0_userdata.0.heos.'+this.pid+".";
        
            this.log('creating HEOS player with pid '+this.pid+' ('+this.ip+')');
        
            this.states = [
                { id:"connected",                   common:{name:"Verbunden?"} },
                { id:"command",                     common:{name:"Befehl an Heos Player senden"} },
                { id:"ip",                          common:{name:"IP-Adresse", write:false} },
                { id:"pid",                         common:{name:"Player-ID", write:false} },
                { id:"name",                        common:{name:"Name des Players", write:false} },
                { id:"model",                       common:{name:"Modell des Players", write:false} },
                { id:"serial",                      common:{name:"Seriennummer des Players", write:false} },
                { id:"last_error",                  common:{name:"Letzte Fehler", write:false} },
                { id:"volume",                      common:{name:"Aktuelle Lautstärke"} },
                { id:"mute",                        common:{name:"Mute aktiviert?"} },
                { id:"play_state",                  common:{name:"Aktueller Wiedergabezustand"} },
                { id:"play_mode_repeat",            common:{name:"Wiedergabewiederholung"} },
                { id:"play_mode_shuffle",           common:{name:"Zufällige Wiedergabe"} },
                { id:"now_playing_media_type",      common:{name:"Aktuelle Wiedergabemedium", write:false} },
                { id:"now_playing_media_song",      common:{name:"Aktuelles Lied", write:false} },
                { id:"now_playing_media_station",   common:{name:"Aktuelle Station", write:false} },
                { id:"now_playing_media_album",     common:{name:"Aktuelle Wiedergabemedium", write:false} },
                { id:"now_playing_media_artist",    common:{name:"Aktueller Artist", write:false} },
                { id:"now_playing_media_image_url", common:{name:"Aktuelles Coverbild", write:false} },
                { id:"now_playing_media_album_id",  common:{name:"Aktuelle Album-ID", write:false} },
                { id:"now_playing_media_mid",       common:{name:"Aktuelle mid", write:false} },
                { id:"now_playing_media_qid",       common:{name:"Aktuelle qid", write:false} },
                { id:"cur_pos",                     common:{name:"lfd. Position"} },
                { id:"duration",                    common:{name:"Dauer", write:false} },
                { id:"cur_pos_MMSS",                common:{name:"lfd. Position MM:SS"} } ,
                { id:"duration_MMSS",               common:{name:"Dauer MM:SS", write:false} },
                { id:"group_leader",                common:{name:"Ist Gruppenleiter", write:false} },
                { id:"group_member",                common:{name:"Ist Gruppenmitglied", write:false} },
                { id:"group_pid",                   common:{name:"PlayerIDs in der Gruppe", write:false} },
                { id:"group_volume",                common:{name:"Lautstärke wenn Gruppen-Leiter"}},
                { id:"group_name",                  common:{name:"Name der Gruppe", write:false} } ,
                { id:"group_mute",                  common:{name:"Gruppe gemutet?"} },
                { id:"script_version",              common:{name:"Installierte Script-Version", write:false} }
            ];
            // beim 1.Start die states erzeugen
            if ( !this.existState("script_version") || this.getState('script_version').val!=SCRIPTVERSION ) {
                this.installed = false;
                this.logWarn('creating HEOS player states for version '+SCRIPTVERSION+', please start script again');
                // states erzeugen
                for (var s=0; s<this.states.length; s++) {
                    this.setState( this.states[s].id);
                }
                this.setState('script_version', SCRIPTVERSION);
            }
            else {
                // Initialisierung der States nach 5 Sek
                setTimeout(() => {
                    this.setState('ip',this.ip);
                    this.setState('name',this.name);
                    this.setState('pid',this.pid);
                    this.setState('model',this.model);
                    this.setState('serial',this.serial);
                    this.sendCommand('get_play_state|get_play_mode|get_now_playing_media|get_volume');
                }, 5000 );
                setTimeout(() => {
                    this.startPlayer();
                }, 10000 );
                this.installed = true;
            }
        }
        
        // über den $-Operator nachsehen, ob der state bereits vorhanden ist
        // getState().notExists geht auch, erzeugt aber Warnmeldungen!
        existState(id) {
            return ( $(this.statePath+id).length==0?false:true);
        }
        
        // wrapper
        getState(id) {
            return getState(this.statePath + id);
        }
        
        // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
        // wenn er noch nicht da ist
        setState(id,value) {
            if ( !this.existState(id) ) this.createState(id, value, undefined);
            else setState( this.statePath + id, value);
        }
        
        // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
        // vorhanden sind (wenn der common-Parameter leer ist)
        createState(id, value, common) {
            if ( !this.existState(id) ) {
                if (common===undefined) {
                    // id im states-Array suchen
                    for (var i=0; i<this.states.length; i++) { 
                        if (this.states[i].id==id) {
                            if (this.states[i].hasOwnProperty('common'))
                                common = this.states[i].common;
                           break;
                        }   
                    }
                }
                if ( (typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                // unter "0_userdata.0"
                let obj = {};
                obj.type = 'state';
                obj.native = {};
                obj.common = common;
                setObject(this.statePath + id, obj, (err) => {
                        if (err) {
                            this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                        } else { 
                            this.log('state "' + this.statePath + id + '" created');
                        }
                });
              
                // value zeitversetzt setzen        
                setTimeout( setState, 3000, this.statePath + id, value );
            }
        }
        
        
        startPlayer() { try {
            this.log('starting HEOS player with pid '+this.pid+' ('+this.ip+')');
            this.onHandler = [];
            // on-Event für command
            this.onHandler.push( on({id: this.statePath+'command', change: "any"}, (obj) => {
                this.executeCommand( obj.id, obj.state.val ) 
            }));
        
            // on-Event für volume (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'volume', change:'ne', ack:false }, (obj) => {
                this.executeCommand( obj.id, 'set_volume&level='+obj.state.val );
            }));
            // on-Event für mute (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'mute', change: 'ne', ack:false}, (obj) => {
                this.executeCommand( obj.id, 'set_mute&state='+ (obj.state.val === true ? 'on' : 'off') );
            }));
            // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'play_mode_shuffle', change: 'ne', ack:false}, (obj) => {
                this.executeCommand( obj.id, 'set_play_mode&shuffle='+ (obj.state.val === true ? 'on' : 'off') );
            }));
            // on-Event für play_state (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'play_state', change: 'ne', ack:false}, (obj) => {
                this.executeCommand( obj.id, 'set_play_state&state='+ obj.state.val );
            }));
        
            // on-Event für group-volume (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'group_volume', change:'ne', ack:false }, (obj) => {
                // "id":"javascript.1.heos.-1746612370.group_volume"
                var id = obj.id.split('.');
                this.executeCommand( 'group/set_volume?gid='+id[3]+'&level='+obj.state.val );
            }));
        
            // on-Event für group-mute (nur wenn ack=false, also über vis)
            this.onHandler.push( on({id: this.statePath+'group_mute', change:'ne', ack:false }, (obj) => {
                // "id":"javascript.1.heos.-1746612370.group_volume"
                var id = obj.id.split('.');
                this.heos.executeCommand( 'group/set_mute?gid='+id[3]+'&state='+(obj.state.val===true ? 'on':'off') );
            }));
        
            this.setState('connected', true);
        } catch(err) { this.logError( 'startPlayer: '+err.message ); } }
        
        // sucht die zur pid passenden player-Insanz
        executeCommand(objID, cmd ) {
            // aus der objID die pid holen
            // objID = javascript.1.heos.394645376.command
            objID = objID.split('.');
            var pid = objID[3];
            if (this.pid == pid ) {
                this.sendCommand( cmd );
            }
         } 
         
        
        stopPlayer() { try {
            this.log('stopping HEOS player with pid '+this.pid+' ('+this.ip+')');
        
            // events unsubcribe
            for (let i=0; i<this.onHandler.length; i++) {
                if (this.onHandler[i]!==undefined) unsubscribe(this.onHandler[i]);
            }
            this.onHandler = [];
            // connected zurücksetzen
            this.setState( "connected", false );
        } catch(err) { this.logError( 'stopPlayer: '+err.message ); } }
        
        /** wandelt einen sek Wert in MM:SS Darstellung um
         **/
        toMMSS (s) {
            var sec_num = parseInt(s, 10); 
            var minutes = Math.floor(sec_num  / 60);
            var seconds = sec_num - (minutes * 60);
            if (seconds < 10) {seconds = "0"+seconds;}
            return minutes+':'+seconds;
        }
        
        setLastError(err) { try {
            this.logWarn(err);
            let val = this.getState('last_error').val;
            let lines = val.splitt('\n');
            if ( lines.length > 4)
                lines.pop();
            lines.unshift(err+'\n');
            this.setState('last_error', lines.toString());
        } catch(e) { this.logError( 'setLastError: '+e.message ); } }
        
        
        /** Auswertung der empfangenen Daten
         **/
        parseResponse (jdata, jmsg, cmd_group, cmd) { try {
            switch (cmd_group) {
                case 'event':
                    switch (cmd) {
                        case 'player_playback_error' :
                            this.setLastError(jmsg.error.replace(/_/g,' '));
                            break;
                        case 'player_state_changed' :
                            this.setState("play_state", jmsg.state);
                            break;
                        case 'player_volume_changed' :
                            this.setState("volume", jmsg.level );
                            this.setState("mute", (jmsg.mute=='on' ? true : false) );
                            break;
                        case 'player_repeat_mode_changed' :
                            this.setState("play_mode_shuffle", jmsg.shuffle );
                            break;
                        case 'player_shuffle_mode_changed' :
                            this.setState("play_mode_repeat", jmsg.repeat );
                            break;
                        case 'player_now_playing_changed' :
                            this.sendCommand('get_now_playing_media');
                            break;
                        case 'player_now_playing_progress' :
                            this.setState("cur_pos", jmsg.cur_pos / 1000);
                            this.setState("cur_pos_MMSS", this.toMMSS(jmsg.cur_pos / 1000));
                            this.setState("duration", jmsg.duration / 1000);
                            this.setState("duration_MMSS", this.toMMSS(jmsg.duration / 1000));
                            break;
                    }        
                    break;
                    
                    
                case 'player':
                    switch (cmd) {
                        case 'set_volume' :
                        case 'get_volume' :
                            if ( getState(this.statePath+"volume").val != jmsg.level)
                                this.setState("volume", jmsg.level);
                            break;
                        case 'set_mute' :
                        case 'get_mute' :
                            this.setState("mute", (jmsg.state=='on' ? true : false) );
                            break;
                        case 'set_play_state' :
                        case 'get_play_state' :
                            this.setState("play_state", jmsg.state);
                            break;
                        case 'set_play_mode' :
                        case 'get_play_mode' :
                            this.setState("play_mode_repeat", jmsg.repeat);
                            this.setState("play_mode_shuffle", (jmsg.shuffle=='on'?true:false) );
                            break;
                        case 'get_now_playing_media' :
                            this.setState("now_playing_media_type", jdata.payload.type);
                            if (jdata.payload.hasOwnProperty('song'))
                                this.setState("now_playing_media_song", jdata.payload.song);
                            if (jdata.payload.hasOwnProperty('album'))
                                this.setState("now_playing_media_album", jdata.payload.album);
                            if (jdata.payload.hasOwnProperty('album_id'))
                                this.setState("now_playing_media_album_id", jdata.payload.album_id);
                            if (jdata.payload.hasOwnProperty('artist'))
                                this.setState("now_playing_media_artist", jdata.payload.artist);
                            if (jdata.payload.hasOwnProperty('image_url'))
                                this.setState("now_playing_media_image_url", jdata.payload.image_url);
                            if (jdata.payload.hasOwnProperty('mid'))
                                this.setState("now_playing_media_mid", jdata.payload.mid);
                            if (jdata.payload.hasOwnProperty('qid'))
                                this.setState("now_playing_media_qid", jdata.payload.qid);
                            if (jdata.payload.hasOwnProperty('station')) {
                                if (jdata.payload.type=='station') {
                                    this.setState("now_playing_media_station", jdata.payload.station);
                                } else {
                                    this.setState("now_playing_media_station", null);
                                }
                            }  
                            break;
                    }
                    break;
            } // switch
        
        
        } catch(err) { this.logError( 'parseResponse: '+err.message ); } }
         
        /** cmd der Form "cmd&param"  werden zur msg heos+cmd+pid+&param aufbereitet
            cmd der Form "cmd?param"  werden zur msg heos+cmd+?param aufbereitet
         **/
        commandToMsg (cmd) {
            var param = cmd.split('&');
            cmd = param[0];
            if ( param.length > 1 ) param='&'+param[1]; else param=''; 
            var cmd_group = 'player';
        
            switch (cmd) {
                case 'get_play_state':
                case 'get_play_mode':
                case 'get_now_playing_media':
                case 'get_volume':
                case 'play_next':
                case 'play_previous':
                case 'set_mute':       // &state=on|off        
                case 'set_volume':     // &level=1..100   
                case 'volume_down':    // &step=1..10   
                case 'volume_up':      // &step=1..10
                case 'set_play_state': // &state=play|pause|stop
                case 'set_play_mode':  // &repeat=on_all|on_one|off  shuffle=on|off
                    break;
        
                // browse            
                case 'play_preset':    // heos://browse/play_preset?pid=player_id&preset=preset_position
                    cmd_group = 'browse';
                    break;
                case 'play_stream':    // heos://browse/play_stream?pid=player_id&url=url_path
                    cmd_group = 'browse';
                    break;
                    
            }        
            return 'heos://'+cmd_group+'/'+cmd+'?pid=' + this.pid + param;
        }
        
        /** Nachricht (command) an player senden
            es sind auch mehrere commands, getrennt mit | erlaubt
            bsp: set_volume&level=20|play_preset&preset=1
         **/
        sendCommand (command) {
            if ( !this.installed ) return;
        
            var cmds = command.split('|');
            for (var c=0; c<cmds.length; c++) {
                this.heos.msgs.push( this.commandToMsg(cmds[c]) );
            }
            this.heos.sendNextMsg();
        }
        
        
        } // end of HeosPlayer
        
        
        /* -----
           Heos
           ----- */
        // Heos Instanz erzeugen und verbinden   
        var heos = new Heos( );
        heos.connect();
        
        // wenn das Script beendet wird, dann auch die Heos Instanz beenden
        onStop(function () { 
            heos.disconnect(); 
        }, 0 );
        
        UhulaU Offline
        UhulaU Offline
        Uhula
        schrieb am zuletzt editiert von
        #101

        @withstu Ja, dass der keep alive nicht funktioniert, habe ich auch schon festgestellt. Vermutlich haben die Player keinen entsprechenden Server implementiert. Den Heartbeat und die anderen Änderungen sehe ich mir an und übernehme sie, danke schön!

        Uhula - Leise und Weise
        Ex: ioBroker on Gigabyte NUC Proxmox

        1 Antwort Letzte Antwort
        0
        • W Offline
          W Offline
          withstu
          schrieb am zuletzt editiert von
          #102

          @Uhula Mein Script hat gerade mein ioBroker lahmgelegt und im Millisekundentakt die Geräte muted/unmuted. Ursache war, dass in den zwei setState Funktionen das ack fehlt:

          // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
          // wenn er noch nicht da ist
          setState(id,value) {
              if ( !this.existState(id) ) this.createState(id, value, undefined);
              else setState( this.statePath + id, value, true);
          }
          

          Btw. ich habe die Events sources_changed/players_changed/groups_changed/group_volume_changed angepasst/hinzugefügt. Dadurch kann ich mir das getPlayers alle 30 Sekunden sparen:

          var jmsg;
          var i;
          var jdata = JSON.parse(response);
          if ( !jdata.hasOwnProperty('heos') || !jdata.heos.hasOwnProperty('command')) 
             return;
          [...]
                  case 'event':
                      switch (cmd) {
                          case 'sources_changed':
                              this.getMusicSources();
                              break;
                          case 'players_changed':
                              this.getPlayers();
                              break;
                          case 'groups_changed' :
                              this.getGroups();
                              break;
                          case 'group_volume_changed' :
                              // "heos": {"command": "event/group_volume_changed ","message": "gid='group_id'&level='vol_level'&mute='on_or_off'"}
                              if ( jmsg.hasOwnProperty('gid') ) {
                                  if ( jmsg.hasOwnProperty('level') ) {
                                      this.setState( jmsg.gid+'.group_volume', jmsg.level);
                                  }
                                  if ( jmsg.hasOwnProperty('mute') ) {
                                      this.setState( jmsg.gid+'.group_mute', (jmsg.mute=='on' ? true : false));
                                  }
                              }
                              break;
                      }
          
          1 Antwort Letzte Antwort
          0
          • B Offline
            B Offline
            Brati
            schrieb am zuletzt editiert von Brati
            #103

            Kann es sein, dass HEOS gerade down ist? Script läuft nicht und in der App kann ich mich auch nicht einloggen...

            ###Edit###

            Der AVR brauchte ein Update, jetzt läuft wieder alles...

            CCU2 - 46 Geräte, ioBroker auf Intel NUC (DN2820FYKH) mit Tab als Frontend, Projekt Gartenhaus mit HM

            W 1 Antwort Letzte Antwort
            0
            • B Brati

              Kann es sein, dass HEOS gerade down ist? Script läuft nicht und in der App kann ich mich auch nicht einloggen...

              ###Edit###

              Der AVR brauchte ein Update, jetzt läuft wieder alles...

              W Offline
              W Offline
              withstu
              schrieb am zuletzt editiert von
              #104

              @Brati Ja ich habe grad auch wieder Probleme mich einzuloggen...

              @Uhula Ich habe in den letzten Tagen noch ein paar Bugs gefixt und das get_players Verhalten umgestellt. Jetzt werden einzelne Player disconnected und nicht mehr alle.

              /****************************
              ### HEOS Script for ioBroker
              
              #### Funktion
              
              Das Script stellt zwei JS Klassen zur Steuerung der Denon HEOS Geräte zur Verfügung. Die class Heos dient dabei dem Erkennen und Steuern der HEOS Geräte. Die class HeosPlayer dient der Interpretation der Antworten der Heos Geräte.
               
              Das Script muss lediglich gestartet werden, es sucht dann im Netzwerk nach HEOS Playern und erzeugt in der aktuellen Javascript-Instanz einen Subeintrag für die Favoriten und je einen Subeintrag für jeden gefundenen Player. Dort wiederum werden State-Variablen zur Aufnahme der Player-Daten angelegt.
               
              Das Script erzeugt auch on-Handler um auf Steuerungen über vis und andere Scripte an den State-Variablen reagieren zu können.
               
              Beim Beenden des Scripts werden alle Verbindungen und on-Handler geschlossen.
              
              Das Script ermöglicht die HEOS Player zu steuern, es soll aber nicht die HEOS App ersetzen. 
               
                
              #### Wichtig!
              
              * Im Javascript-Adapter muss in der Instanz-Konfiguration "node-ssdp" mit angegeben werden! Alternativ kann die Bibliothek auch komplett über "npm install node-ssdp" installiert werden.
              * Wenn mit Favoriten (Presets) gearbeitet werden soll, müssen die HEOS-Konto Logindaten in den beiden Konstanten HEOS_USERNAME (EmailAdr) und HEOS_PASSWORD hier im Script in der Konfiguration angegeben werden (so, wie in der HEOS App)!
              * Eine Konfiguration von IP-Adressen und Player-IDs ist nicht notwendig!
              * U.U. kann es notwendig sein das Script nach dem 1.Start zu beenden und nach 30 Sek erneut zu starten, da die Neuanlage der ioBroker States etwas Zeit benötigt. Warnungen sind dabei zu ignorieren. ;-)
              
              #### Updates
               
              ##### v2.0 13.03.2020
              * das Script überprüft nun, ob alle notwendigen states für Heos und HeosPlayer im ioBroker korrekt erzeugt wurden und gibt eine Warnung mit Script-Neustartaufforderung aus, wenn die states nicht vorhanden sind. Dieses ist notwendig, da das Anlegen von states asynchron erfolgt und einige ms dauern kann
              * (WICHTIG!) die states werden nicht mehr in der aktuellen Javascript-Instanz und auch nicht mehr unter der IP des Heos-Players gespeichert, sondern Javascript-Instanzunabhängig unter 0_userdata.0 und seiner Player-ID (pid), da diese sich nicht ändert. Die IP hingegen u.U. schon. Also statt "javascript.X.heos.192_168_2_43" nun als "0_userdata.0.heos.12345678". Wer bereits auf die alten Werte im VIS zugreift, muss dieses im VIS anpassen!  
              * es wurden Befehle/states für die Gruppensteuerung der Heos-Player hinzugefügt. Beim Start werden die Gruppen ausgelesen und in den Player-states des Gruppenleiters (der erste genannte Player) gespeichert. Über dessen states kann die Gruppe gesteuert werden: 
                  group_volume: dient der Steuerung der Gruppen-Lautstärke
                  group_mute: dient der Steuerung der Gruppen-Mutes
                  group_leader: ist true, wenn der Player der Gruppenleiter ist
                  group_member: ist true, wenn der Player Mitglied einer Gruppe ist
              * alle 60 Sek wird überprüft, ob noch alle HEOS-Player erreichbar sind bzw. neue/reconnectete hinzugekommen sind. Neue/reconnectete werden der Liste der HEOS-Player hinzugefügt, fehlende werden gestoppt. Da hierzu das HEOS-Netzwerk gefragt wird (get_players Meldung), kann es bis zu 5 Min dauern bis Änderungen erkannt werden. Der neue HEOS-Player-State "connected" wird entsprechend gesetzt
              * jeder HEOS-Player hat einen neuen state "connected", dieser wird nach erfolgreichem Start auf true gesetzt, bei korrektem Beenden des Scripts auf false
              * diverse Filter/Korrekturen aus dem Forum übernommen, vielen dank an withstu
                
                
               #### class Heos
               
               Diese Basisklasse dient 
              
              * dem Erkennen von HEOS Geräten (Playern). Das Erkennen der HEOS Geräte findet via UPD unter Nutzung von node-ssdp statt. node-ssdp muss dazu im Javascript-Adapter in der Konfiguration mit angegeben werden!
              * der Kommunikation über TelNet. Es wird genau eine TelNet Verbindung zu einem HEOS Gerät aufgebaut, dieses reicht die Sendungen und Antworten zentral weiter
              * der Ermittlung von Favoriten (Presets). Für jeden Favorit wird ein ioBroker State heos.presets.n mit entsprechenden Sub-States erzeugt. Zur Nutzung der Presets ist ein SignIn notwendig, hierzu müssen HEOS_USERNAME und HEOS_PASSWORD gesetzt werden.
              * dem Instanziieren der class HeosPlayer je HEOS Gerät. Je HEOS Gerät wird ein ioBroker-State mit der IP-Adresse des Players erzeugt, dieser State erhält diverse Sub-States
                
              ##### State-Variable: Heos
               
              Werden angelegt unter "0_userdata.0.heos."
              
              * connected: true wenn die Verbindung zu mindestens einem HEOS-Player besteht
              * script_version: Version des Scripts, dient dazu Script-Updates zu erkennen
              * last_error: Letzter Fehlertext
              * command(cmd): Hierüber können der Heos-Klasse Befehle übergeben werden, für cmd gilt:
                  "connect": Verbindung zu HEOS aufbauen bzw. erneut aufbauen (praktisch ein reset)
                  "disconnect": Verbindung zu HEOS beenden
                  "load_presets": lädt die Favoriten neu
                
                  "group/set_group?pid=<pid1>,<pid2>,...": setzen einer Gruppe, die pids sind die der Player wie sie unter den Objekten für jeden Player abgelegt sind. Bsp: "group/set_group?pid=12345678,12345679". 
               
                 "group/set_group?pid=<pid1>" : hebt die Gruppierung des Players mit der pid1 wieder auf. Bsp: "group/set_group?pid=12345678"
                 "...": alle anderen cmd-Werte werden "as is" versucht an HEOS zu senden
               
                
              * presets.<n>: Hierunter werden die Favoriten, Presets angelegt. Je Favorit ein Unterordner n=1 bis Anzahl. Darunter befinden sich dann die States, welche den Inhalt der Favoriten aufnehmen:
               
              * image_url (read): Bild des Favoriten 
              * name (read): Name des Favoriten
              * playable (read): Spielbar? true/false
              * type (read): Typ des Favoriten (station, ...)
               
                  
                 
               #### class HeosPlayer 
               
               Diese Klasse dient
              * der Steuerung genau eines HEOS Gerätes. Hierzu wird die zentrale Telnet Verbindung der class Heos genutzt.
              * dem Erzeugen der ioBroker-States zum Speichern der Geräte-Werte
              * der Auswertung von Antworten der HEOS Geräte und Zuweisung an die entsprechenden ioBroker-States
               
              ##### State-Variable
              
              Werden angelegt unter "0_userdata.0.heos.<pid>"
              
              * connected : true, wenn eine Verbindung besteht, sonst false
              * command(cmd): Hierüber können dem Heos-Player Befehle übergeben werden. Diese werden im Klartext in die State-Variable geschrieben. Getrennt durch das | Zeichen können mehrere hintereinander eingetragen werden. Bsp: Setzen der Lautstärke auf 20 und Abspielen des 1.Favoriten "set_volume&level=20|play_preset&preset=1|set_play_state&state=play". Folgende cmd sind erlaubt:
              
                "set_volume&level=0|1|..|100" : Setzt die gewünschte Lautstärke 
                "set_play_state&state=play|pause|stop" : Startet und stoppt die Wiedergabe
                "set_play_mode&repeat=on_all|on_one|off&shuffle=on|off": Setzt Wiederholung und Zufallsweidergabe
                "set_mute&state=on|off" : Stumm schalten oder nicht
                "volume_down&step=1..10" : Lautstärke verringern um   
                "volume_up&step=1..10"  : Lauststäre erhöhen um
                "play_next"  : Nächsten Titel spielen
                "play_previous" : Vorherigen Titel spielen
                "play_preset&preset=1|2|..|n" : Favorit Nr n abspielen
                "play_stream&url=url_path" : URL-Stream abspielen
               
              * cur_pos (read) : lfd. Position der Wiedergabe in [Sek]
              * cur_pos_MMSS (read) : lfd. Position der Wiedergabe im Format MM:SS
              * duration (read) : Länge des aktuellen Titels in [Sek]
              * duration_MMSS (read) : Länge des aktuellen Titels im Format MM:SS
              * ip (read): IP-Adresse des HEOS Players
              * last_error (read): Text des letzten Fehlers, der vom Player gesendet wurde. Wird bei jedem neuen Befehl zurückgesetzt. Wenn man bspw. versucht eine Wiedergabe über Amazon o.ä. zu starten und es gibt aber keine Verbindung dahin, steht hier der Fehlertext drin
              * model (read): Modell des HEOS Players
              * mute (read write): Boolsche Variable, die anzeigt ob der Player gemutet (Stumm geschaltet) wurde. Hierüber kann auch ein mute gesetzt werden
              * name (read): Name des HEOS Players
              * now_playing_media_... (read) : Eine Gruppe von States, in welchen Infos über den aktuellen Titel gespeichert werden, wird automatisch aktualisiert. 
              * pid (read): Player-ID des HEOS Players
              * play_mode_repeat (read write) : Repeat-Modus der Wiedergabe. Mögliche Werte: on_all|on_one|off  
              * play_mode_shuffle (read write) : Zufallswiedergabe true/false
              * play_state (read write): Zustand des Players. Mögliche Werte play|pause|stop
              * serial (read): Seriennummmer des HEOS Players
              * volume (read write): Lautstärke im Bereich 0 - 100. 
              * group_leader : Ist Gruppenleiter
              * group_member : Ist Gruppenmitglied
              * group_pid : Player pids in der Gruppe
              * group_volume : Lautstärke wenn Gruppen-Leiter
              * group_name : Name der Gruppe
              * group_mute : Gruppe gemutet?
              
               
              #### Weiterführende Links
              
              * HEOS CLI Protokoll: http://rn.dmglobal.com/euheos/HEOS_CLI_ProtocolSpecification.pdf
              * http://forum.iobroker.net/viewtopic.php?f=30&t=5693&p=115554#p115554
               
               
              (c) Uhula, MIT License, no warranty, use on your own risc
               
              */
              
              /****************************
               * Konfiguration
               ****************************/
              
              const HEOS_USERNAME = '';
              const HEOS_PASSWORD = '';
              
              const HEARTBEAT_INTERVAL = 15000;
              const HEARTBEAT_TIMEOUT = 60000;
              
              
              /****************************
               * ab hier nichts mehr ändern ;-) 
               ****************************/
              
              var net = require('net');
              
              const stateDISCONNECTED = 0;
              const stateSEARCHING = 1;
              const stateCONNECTING = 2;
              const stateCONNECTED = 3;
              const SCRIPTVERSION = '2.0/2020-03-21';
              
              /********************
               * class Heos
               ********************/
              class Heos {
              
                  logDebug(msg) { console.debug('[Heos] ' + msg); }
                  log(msg) { console.log('[Heos] ' + msg); }
                  logWarn(msg) { console.warn('[Heos] ' + msg); }
                  logError(msg) { console.error('[Heos] ' + msg); }
              
                  constructor() {
                      this.init();
                      this.states = [
                          { id: "command", common: { name: "Kommando für HEOS Aufrufe" } },
                          { id: "connected", common: { name: "Verbunden?", write: false, def: false } },
                          { id: "last_error", common: { name: "Letzte Fehler", write: false } },
                          { id: "script_version", common: { name: "Installierte Script-Version", write: false } }
                      ];
                      // beim 1.Start nur die States erzeugen
                      if (!this.existState("script_version") || (this.getState('script_version').val != SCRIPTVERSION)) {
                          this.installed = false;
                          this.logWarn('creating HEOS states for version ' + SCRIPTVERSION + ', please start script again');
                          // Anlage der States 
                          for (var s = 0; s < this.states.length; s++) {
                              this.setState(this.states[s].id);
                          }
                          this.setState('script_version', SCRIPTVERSION);
                      }
                      else {
                          this.installed = true;
                          on({ id: this.statePath + 'command', change: "any" }, (obj) => {
                              this.executeCommand(obj.state.val);
                          });
                      }
                  }
              
              
              
                  // Initialisierung
                  init() {
                      this.statePath = '0_userdata.0.heos.';
                      this.players = {};
                      this.heartbeatInterval = undefined;
                      this.heartbeatTimeout = undefined;
                      this.ssdpSearchInterval = undefined;
                      this.net_client = undefined;
                      this.nodessdp_client = undefined;
              
                      this.ip = '';
                      this.msgs = [];
                      this.lastResponse = '';
                      this.state = stateDISCONNECTED;
                      this.unfinishedResponses = '';
                      this.ssdpSearchTargetName = 'urn:schemas-denon-com:device:ACT-Denon:1';
                  }
              
              
                  // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                  // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                  existState(id) {
                      return ($(this.statePath + id).length == 0 ? false : true);
                  }
              
                  // wrapper
                  getState(id) {
                      return getState(this.statePath + id);
                  }
              
                  // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
                  // wenn er noch nicht da ist
                  setState(id, value) {
                      if (!this.existState(id)) this.createState(id, value, undefined);
                      else setState(this.statePath + id, value, true);
                  }
              
                  // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
                  // vorhanden sind (wenn der common-Parameter leer ist)
                  createState(id, value, common) {
                      if (!this.existState(id)) {
                          if (common === undefined) {
                              // id im states-Array suchen
                              for (var i = 0; i < this.states.length; i++) {
                                  if (this.states[i].id == id) {
                                      if (this.states[i].hasOwnProperty('common'))
                                          common = this.states[i].common;
                                      break;
                                  }
                              }
                          }
                          if ((typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                          // unter "0_userdata.0"
                          let obj = {};
                          obj.type = 'state';
                          obj.native = {};
                          obj.common = common;
                          setObject(this.statePath + id, obj, (err) => {
                              if (err) {
                                  this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                              } else {
                                  this.log('state "' + this.statePath + id + '" created');
                              }
                          });
              
                          // value zeitversetzt setzen        
                          setTimeout(setState, 3000, this.statePath + id, value);
                      }
                  }
              
                  /** Verbindung zum HEOS System herstellen
                   **/
                  connect() {
                      if (!this.installed) return;
              
                      try {
                          this.log("searching for HEOS devices ...")
                          this.setState("connected", false);
                          this.state = stateSEARCHING;
                          const NodeSSDP = require('node-ssdp').Client;
                          this.nodessdp_client = new NodeSSDP();
                          this.nodessdp_client.explicitSocketBind = true;
                          this.nodessdp_client.on('response', (headers, statusCode, rinfo) => this.onNodeSSDPResponse(headers, statusCode, rinfo));
                          this.nodessdp_client.on('error', error => { this.nodessdp_client.close(); this.logError(error); });
                          this.nodessdp_client.search(this.ssdpSearchTargetName);
                          this.ssdpSearchInterval = setInterval(() => {
                              this.log("still searching for HEOS devices ...")
                              this.nodessdp_client.search(this.ssdpSearchTargetName);
                          }, 30000);
                      } catch (err) { this.logError('connect: ' + err.message); }
              
                  }
              
                  /** Alle Player stoppen und die TelNet Verbindung schließen 
                   **/
                  disconnect() {
                      this.log('disconnecting from HEOS ...');
                      unsubscribe(this.statePath.substr(0, this.statePath.length - 1));
              
                      this.stopHeartbeat();
                      this.stopPlayers();
              
                      if (typeof this.net_client !== 'undefined') {
                          this.registerChangeEvents(false);
                          this.net_client.destroy();
                          this.net_client.unref();
                      }
                      if (typeof this.nodessdp_client !== 'undefined') {
                          this.nodessdp_client.stop();
                      }
                      this.setState("connected", false);
                      this.state = stateDISCONNECTED;
                      this.log('disconnected from HEOS');
                  }
              
                  reconnect() {
                      if (this.state == stateCONNECTED) {
                          this.log('reconnecting to HEOS ...');
                          this.disconnect();
                          setTimeout(() => {
                              this.init();
                              this.connect();
                          }, 5000);
                      }
                  }
              
                  executeCommand(cmd) {
                      //l('command: '+cmd);
                      switch (cmd) {
                          case 'load_presets':
                              this.getMusicSources();
                              break;
                          case 'group/get_groups':
                              this.getGroups();
                              break;
                          case 'connect':
                              this.disconnect();
                              this.init();
                              this.connect();
                              break;
                          case 'disconnect':
                              this.disconnect();
                              break;
                          default:
                              if (this.state == stateCONNECTED) {
                                  this.msgs.push('heos://' + cmd + '\n');
                                  this.sendNextMsg();
                              }
              
                      }
                  }
                  /** es wurde mindestens ein Player erkannt, nun über dessen IP alle bekannten HEOS Player
                   *  durch senden von "player/get_players" ermitteln
                   */
                  onNodeSSDPResponse(headers, statusCode, rinfo) {
                      try {
                          // rinfo {"address":"192.168.2.225","family":"IPv4","port":53871,"size":430}
                          if (typeof this.net_client == 'undefined') {
                              if (headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                                  this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
                              } else {
                                  if (this.ssdpSearchInterval) {
                                      clearInterval(this.ssdpSearchInterval);
                                      this.ssdpSearchInterval = undefined;
                                  }
              
                                  this.ip = rinfo.address;
                                  this.log('connecting to HEOS (' + this.ip + ') ...');
                                  this.net_client = net.connect({ host: this.ip, port: 1255 });
                                  this.net_client.setKeepAlive(true, 5000);
                                  this.net_client.setNoDelay(true);
                                  this.net_client.setTimeout(15000);
              
                                  this.state = stateCONNECTING;
              
                                  this.net_client.on('error', (error) => {
                                      this.logError(error);
                                      this.reconnect();
                                  });
              
                                  this.net_client.on('connect', () => {
                                      this.setState("connected", true);
                                      this.state = stateCONNECTED;
                                      this.log('connected to HEOS (' + this.ip + ')');
                                      this.getPlayers();
                                      this.registerChangeEvents(true);
                                      this.signIn();
                                      this.getMusicSources();
                                      this.getGroups();
                                      this.startHeartbeat();
                                  });
              
                                  // Gegenseite hat die Verbindung geschlossen 
                                  this.net_client.on('end', () => {
                                      this.logWarn('HEOS closed the connection to ' + this.ip);
                                      this.reconnect();
                                  });
              
                                  // timeout
                                  this.net_client.on('timeout', () => {
                                      this.logWarn('Timeout trying connect to ' + this.ip);
                                      this.reconnect();
                                  });
              
                                  // Datenempfang
                                  this.net_client.on('data', (data) => this.onData(data));
                              }
                          }
                      } catch (err) { this.logError('onNodeSSDPResponse: ' + err.message); }
                  }
              
                  setLastError(err) {
                      this.logWarn(err);
                      let val = this.getState('last_error').val + '';
                      let lines = val.split('\n');
                      if (lines.length > 4)
                          lines.pop();
                      lines.unshift(err + '\n');
                      this.setState('last_error', lines.toString());
                  }
              
              
                  /** es liegen Antwort(en) vor
                   * 
                   * {"heos": {"command": "browse/browse", "result": "success", "message": "sid=1028&returned=9&count=9"}, 
                   *    "payload": [
                   *        {"container": "no", "mid": "s25529", "type": "station", "playable": "yes", "name": "NDR 1 Niedersachsen (Adult Hits)", "image_url": "http://cdn-profiles.tunein.com/s25529/images/logoq.png?t=154228"}, 
                   *        {"container": "no", "mid": "s56857", "type": "station", "playable": "yes", "name": "NDR 2 Niedersachsen 96.2 (Top 40 %26 Pop Music)", "image_url": "http://cdn-profiles.tunein.com/s56857/images/logoq.png?t=154228"}, 
                   *        {"container": "no", "mid": "s24885", "type": "station", "playable": "yes", "name": "NDR Info", "image_url": "http://cdn-profiles.tunein.com/s24885/images/logoq.png?t=1"}, {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
                   *        {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}, 
                   *        {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
                   *        {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk"
                   **/
                  onData(data) {
                      try {
                          data = data.toString();
                          data = data.replace(/[\n\r]/g, '');    // Steuerzeichen "CR" entfernen   
                          // es können auch mehrere Antworten vorhanden sein! {"heos": ... } {"heos": ... }
                          // diese nun in einzelne Antworten zerlegen
                          data = this.unfinishedResponses + data;
                          this.unfinishedResponses = '';
              
                          data = data.replace(/{"heos":/g, '|{"heos":');
                          var responses = data.split('|');
                          responses.shift();
                          for (var r = 0; r < responses.length; r++) if (responses[r].trim().length > 0) {
                              try {
                                  JSON.parse(responses[r]); // check ob korrektes JSON Array
                                  this.parseResponse(responses[r]);
                              } catch (e) {
                                  this.logDebug('onData: invalid json (error: ' + e.message + '): ' + responses[r]);
                                  this.unfinishedResponses += responses[r];
                              }
                          }
                          // wenn weitere Msg zum Senden vorhanden sind, die nächste senden
                          if (this.msgs.length > 0)
                              this.sendNextMsg();
                      } catch (err) { this.logError('onData: ' + err.message); }
                  }
              
                  /** Antwort(en) verarbeiten. Sich wiederholende Antworten ignorieren
                   **/
                  parseResponse(response) {
                      try {
                          this.logDebug('parseResponse: ' + response);
              
                          if (response == this.lastResponse || response.indexOf("command under process") > 0)
                              return
                          this.lastResponse = response;
              
                          var jmsg;
                          var i;
                          var jdata = JSON.parse(response);
                          if (!jdata.hasOwnProperty('heos') || !jdata.heos.hasOwnProperty('command'))
                              return;
              
                          // msg auswerten
                          try {
                              jmsg = '{"' + decodeURI(jdata.heos.message).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"').replace(/\s/g, '_') + '"}';
                              jmsg = JSON.parse(jmsg);
                          } catch (err) {
                              jmsg = {};
                          }
              
                          // result ?
                          var result = 'success';
                          if (jdata.heos.hasOwnProperty('result')) result = jdata.heos.result;
                          if (result != 'success') {
                              this.setLastError('result=' + result + ', ' + jmsg.text);
                          }
              
                          // cmd auswerten
                          var cmd = jdata.heos.command.split('/');
                          var cmd_group = cmd[0];
                          cmd = cmd[1];
                          switch (cmd_group) {
                              case 'system':
                                  switch (cmd) {
                                      case 'heart_beat':
                                          this.resetHeartbeatTimeout();
                                          break;
                                  }
                                  break;
                              case 'event':
                                  switch (cmd) {
                                      case 'players_changed':
                                          this.getPlayers();
                                          break;
                                      case 'groups_changed':
                                          this.getGroups();
                                          break;
                                      case 'group_volume_changed':
                                          // "heos": {"command": "event/group_volume_changed ","message": "gid='group_id'&level='vol_level'&mute='on_or_off'"}
                                          if (jmsg.hasOwnProperty('gid')) {
                                              if (jmsg.hasOwnProperty('level')) {
                                                  this.setState(jmsg.gid + '.group_volume', jmsg.level);
                                              }
                                              if (jmsg.hasOwnProperty('mute')) {
                                                  this.setState(jmsg.gid + '.group_mute', (jmsg.mute == 'on' ? true : false));
                                              }
                                          }
                                          break;
                                  }
                                  break;
                              case 'player':
                                  switch (cmd) {
                                      // {"heos": {"command": "player/get_players", "result": "success", "message": ""}, 
                                      //  "payload": [{"name": "HEOS Bar", "pid": 1262037998, "model": "HEOS Bar", "version": "1.430.160", "ip": "192.168.2.225", "network": "wifi", "lineout": 0, "serial": "ADAG9170202780"}, 
                                      //              {"name": "HEOS 1 rechts", "pid": -1746612370, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.201", "network": "wifi", "lineout": 0, "serial": "AMWG9170934429"}, 
                                      //              {"name": "HEOS 1 links", "pid": 68572158, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.219", "network": "wifi", "lineout": 0, "serial": "AMWG9170934433"}
                                      //             ]}
                                      case 'get_players':
                                          if (jdata.hasOwnProperty('payload')) {
                                              this.startPlayers(jdata.payload);
                                          }
                                          break;
                                  }
                                  break;
              
                              // {"heos": {"command": "browse/get_music_sources", "result": "success", "message": ""}, 
                              //  "payload": [{"name": "Amazon", "image_url": "https://production...png", "type": "music_service", "sid": 13}, 
                              //              {"name": "TuneIn", "image_url": "https://production...png", "type": "music_service", "sid": 3}, 
                              //              {"name": "Local Music", "image_url": "https://production...png", "type": "heos_server", "sid": 1024}, 
                              //              {"name": "Playlists", "image_url": "https://production...png", "type": "heos_service", "sid": 1025}, 
                              //              {"name": "History", "image_url": "https://production...png", "type": "heos_service", "sid": 1026}, 
                              //              {"name": "AUX Input", "image_url": "https://production...png", "type": "heos_service", "sid": 1027}, 
                              //              {"name": "Favorites", "image_url": "https://production...png", "type": "heos_service", "sid": 1028}]}
                              case 'browse':
                                  switch (cmd) {
                                      case 'get_music_sources':
                                          if ((jdata.hasOwnProperty('payload'))) {
                                              for (i = 0; i < jdata.payload.length; i++) {
                                                  var source = jdata.payload[i];
                                                  if (source.name == 'Favorites') {
                                                      this.browse(source.sid);
                                                  }
                                              }
                                          }
              
                                          break;
              
                                      // {"heos": {"command": "browse/browse", "result": "success", "message": "pid=1262037998&sid=1028&returned=5&count=5"}, 
                                      //  "payload": [{"container": "no", "mid": "s17492", "type": "station", "playable": "yes", "name": "NDR 2 (Adult Contemporary Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s17492q.png"}, 
                                      //              {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
                                      //              {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk", "type": "station", "playable": "yes", "name": "Ed Sheeran", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/EdSheeran._SX200_SY200_.jpg"}, 
                                      //              {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
                                      //              {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}], 
                                      //  "options": [{"browse": [{"id": 20, "name": "Remove from HEOS Favorites"}]}]}                    
                                      case 'browse':
                                          if ((jdata.hasOwnProperty('payload'))) {
                                              for (i = 0; i < jdata.payload.length; i++) {
                                                  var preset = jdata.payload[i];
                                                  this.createState('presets.' + (i + 1) + '.name', preset.name, { name: 'Favoritenname ' });
                                                  this.createState('presets.' + (i + 1) + '.playable', (preset.playable == 'yes' ? true : false), { name: 'Favorit ist spielbar' });
                                                  this.createState('presets.' + (i + 1) + '.type', preset.type, { name: 'Favorittyp' });
                                                  this.createState('presets.' + (i + 1) + '.image_url', preset.image_url, { name: 'Favoritbild' });
                                              }
                                          }
                                          break;
                                  }
                                  break;
              
                              case 'group':
                                  //l('group: '+response);
                                  switch (cmd) {
                                      // { "heos":{"command":"player/set_group","result":"success",
                                      //           "message": "gid='new group_id'&name='group_name'&pid='player_id_1, player_id_2,…,player_id_n'
                                      //          } 
                                      // }
                                      case 'set_group':
                                          this.setGroup(jmsg);
                                          break;
              
                                      // { "heos": {"command":"group/get_volume","result":"success","message": "gid='group_id'&level='vol_level'"}
                                      case 'get_volume':
                                          if (jmsg.hasOwnProperty('gid')) {
                                              if (jmsg.hasOwnProperty('level')) {
                                                  this.setState(jmsg.gid + '.group_volume', jmsg.level);
                                              }
                                          }
                                          break;
              
                                      // { "heos": {"command":"group/get_mute","result":"success","message": "gid='group_id'&state='on_or_off'"}
                                      case 'get_mute':
                                          if (jmsg.hasOwnProperty('gid')) {
                                              if (jmsg.hasOwnProperty('state')) {
                                                  this.setState(jmsg.gid + '.group_mute', (jmsg.state == 'on' ? true : false));
                                              }
                                          }
                                          break;
              
              
                                      // { "heos": { "command": "player/get_groups", "result": "success", "message": "" },
                                      //   "payload": [{"name":"'group name 1'", "gid": "group id 1'",
                                      //                "players":[{"name":"player name 1","pid":"'player id1'","role":"player role 1 (leader or member)'"},
                                      //                           {"name":"player name 2","pid":"'player id2'","role":"player role 2 (leader or member)'"} 
                                      //                          ]
                                      //               },
                                      //               {"name":"'group name 2'","gid":"group id 2'",
                                      //                "players":[{"name":"player name ... 
                                      case 'get_groups':
                                          // bisherige groups leeren
                                          var objs = $(this.statePath + '*.group_name');
                                          for (var o = 0; o < objs.length; o++) setState(objs[o], 'no group');
                                          objs = $(this.statePath + '*.group_leader');
                                          for (var o = 0; o < objs.length; o++) setState(objs[o], false);
                                          objs = $(this.statePath + '*.group_member');
                                          for (var o = 0; o < objs.length; o++) setState(objs[o], false);
                                          objs = $(this.statePath + '*.group_pid');
                                          for (var o = 0; o < objs.length; o++) setState(objs[o], '');
              
                                          // payload mit den groups auswerten
                                          if ((jdata.hasOwnProperty('payload'))) {
                                              for (i = 0; i < jdata.payload.length; i++) {
                                                  var group = jdata.payload[i];
                                                  var players = group.players;
                                                  // Player IDs addieren. Hinweis: "leader" ist nicht immer der 1.Playereintrag
                                                  group.pid = "";
                                                  for (var p = 0; p < players.length; p++) {
                                                      if (players[p].role == 'leader')
                                                          group.pid = players[p].pid + (group.pid.length > 0 ? "," : "") + group.pid;
                                                      else
                                                          group.pid = group.pid + (group.pid.length > 0 ? "," : "") + players[p].pid;
                                                  }
                                                  this.setGroup(group);
                                              }
                                          }
                                          break;
              
                                  }
                                  break;
              
              
                              case 'system':
                                  switch (cmd) {
                                      case 'sign_in':
                                          this.log('signed in: ' + jdata.heos.result);
                                          break;
                                  }
                                  break;
                          }
              
              
                          // an die zugehörigen Player weiterleiten
                          if (jmsg.hasOwnProperty('pid')) {
                              if(jmsg.pid in this.players){
                                  this.players[jmsg.pid].parseResponse(jdata, jmsg, cmd_group, cmd);
                              }
                          }
              
              
                      } catch (err) { this.logError('parseResponse: ' + err.message + '\n ' + response); }
                  }
              
              
                  // sucht die zur pid passenden player-Insanz
                  sendCommandToPlayer(objID, cmd) {
                      // aus der objID die pid holen
                      // objID = javascript.1.heos.394645376.command
                      objID = objID.split('.');
                      var pid = objID[3];
                      if(pid in this.players){
                          this.players[pid].sendCommand(cmd);
                      }
                  }
              
                  stopPlayer(pid){
                      try {
                          let heosPlayer = this.players[pid];
                          if (heosPlayer)
                              heosPlayer.stopPlayer();
                          // player leeren
                          delete this.players[pid];
                      } catch (err) { this.logError('stopPlayer: ' + err.message); }
                  }
              
                  // Für die gefundenen HEOS Player entsprechende class HeosPlayer Instanzen bilden und nicht mehr verbundene Player stoppen
                  startPlayers(payload) {
                      try {
                          var connectedPlayers = [];
                          for (var i = 0; i < payload.length; i++) {
                              var player = payload[i];
                              var pid = player.pid + ''; //Convert to String
                              if(!(pid in this.players)){
                                  this.players[pid] = new HeosPlayer(this, player);
                              }
                              connectedPlayers.push(pid);
                          }
                          //Remove disconnected players
                          for(var pid in this.players) {
                              if(!connectedPlayers.includes(pid)){
                                  this.stopPlayer(pid);
                              }
                          }
                      } catch (err) { this.logError('startPlayers: ' + err.message); }
                  }
              
                  //Alle Player stoppen
                  stopPlayers() {
                      this.logDebug("Try to stop players:" + JSON.stringify(Object.keys(this.players)));
                      for (var pid in this.players) {
                          this.stopPlayer(pid);
                      }
                  }
              
                  // setzen der Werte einer Group
                  setGroup(group) {
                      if (group.hasOwnProperty('pid')) {
                          // in den Playern den Groupstatus setzen
                          var pids = group.pid.split(',');
              
                          for (var i = 0; i < pids.length; i++) {
                              this.setState(pids[i] + '.group_name', (group.hasOwnProperty('name') ? group.name : ''));
                              this.setState(pids[i] + '.group_pid', group.pid);
                              this.setState(pids[i] + '.group_leader', (i == 0) && (pids.length > 1));
                              this.setState(pids[i] + '.group_member', (pids.length > 1));
                          }
              
                          if (group.hasOwnProperty('gid')) {
                              // volume und mute dazu holen
                              this.executeCommand("group/get_volume?gid=" + group.gid);
                              this.executeCommand("group/get_mute?gid=" + group.gid);
                          }
                      }
              
                  }
              
                  getPlayers() {
                      if (this.state == stateCONNECTED) {
                          this.msgs.push('heos://player/get_players\n');
                          this.sendNextMsg();
                      }
                  }
              
                  registerChangeEvents(b) {
                      if (this.state == stateCONNECTED) {
                          if (b) this.msgs.push('heos://system/register_for_change_events?enable=on');
                          else this.msgs.push('heos://system/register_for_change_events?enable=off');
                          this.sendNextMsg();
                      }
                  }
              
                  signIn() {
                      if (this.state == stateCONNECTED) {
                          // heos://system/sign_in?un=heos_username&pw=heos_password
                          this.msgs.push('heos://system/sign_in?un=' + HEOS_USERNAME + '&pw=' + HEOS_PASSWORD);
                          this.sendNextMsg();
                      }
                  }
              
                  getMusicSources() {
                      if (this.state == stateCONNECTED) {
                          // heos://browse/get_music_sources
                          this.msgs.push('heos://browse/get_music_sources');
                          this.sendNextMsg();
                      }
              
                  }
              
                  getGroups() {
                      if (this.state == stateCONNECTED) {
                          // heos://group/get_groups
                          this.msgs.push('heos://group/get_groups');
                          this.sendNextMsg();
                      }
              
                  }
              
                  startHeartbeat() {
                      if (this.state == stateCONNECTED) {
                          this.logDebug("start heartbeat interval");
                          this.heartbeatInterval = setInterval(() => {
                              this.logDebug("heartbeat")
                              this.msgs.push('heos://system/heart_beat');
                              this.sendNextMsg();
                              if (typeof this.heartbeatTimeout == undefined) {
                                  this.heartbeatTimeout = setTimeout(() => {
                                      this.log("heartbeat timeout");
                                      this.reboot();
                                      setTimeout(() => {
                                          this.reconnect();
                                      }, 1000)
                                  }, HEARTBEAT_TIMEOUT);
                              }
                          }, HEARTBEAT_INTERVAL);
                      }
                  }
              
                  resetHeartbeatTimeout() {
                      this.logDebug("reset heartbeat timeout");
                      if (this.heartbeatTimeout) {
                          clearTimeout(this.heartbeatTimeout);
                          this.heartbeatTimeout = undefined;
                      }
                  }
              
                  stopHeartbeat() {
                      this.logDebug("stop heartbeat interval");
                      if (this.heartbeatInterval) {
                          clearInterval(this.heartbeatInterval);
                          this.heartbeatInterval = undefined;
                      }
                      this.resetHeartbeatTimeout();
                  }
              
                  reboot() {
                      if (this.state == stateCONNECTED) {
                          this.logDebug("reboot device");
                          // heos://system/reboot
                          this.msgs.push('heos://system/reboot');
                          this.sendNextMsg();
                      }
                  }
              
                  browse(sid) {
                      if (this.state == stateCONNECTED) {
                          // heos://browse/browse?sid=source_id
                          this.msgs.push('heos://browse/browse?sid=' + sid);
                          this.sendNextMsg();
                      }
                  }
              
              
                  sendNextMsg() {
                      if (this.msgs.length > 0) {
                          var msg = this.msgs.shift();
                          this.sendMsg(msg);
                      }
                  }
              
                  // Nachricht an player senden
                  sendMsg(msg) {
                      this.net_client.write(msg + "\n");
                      this.logDebug("data sent: " + msg);
                  }
              
              
              } // end of class Heos
              
              /********************
               * class HeosPlayer
               ********************/
              
              class HeosPlayer {
              
                  logDebug(msg) { console.debug('[HeosPlayer ' + this.pid + '] ' + msg); }
                  log(msg) { console.log('[HeosPlayer ' + this.pid + '] ' + msg); }
                  logWarn(msg) { console.warn('[HeosPlayer ' + this.pid + '] ' + msg); }
                  logError(msg) { console.error('[HeosPlayer ' + this.pid + '] ' + msg); }
              
                  constructor(heos, player) {
                      this.heos = heos;
                      this.ip = player.ip;
                      this.name = player.name;
                      this.pid = player.pid;
                      this.model = player.model;
                      this.serial = player.serial;
                      this.onHandler = [];
              
                      //    this.statePath = 'javascript.'+instance+'.heos.'+this.ip.replace(/\./g,'_')+".";
                      this.statePath = '0_userdata.0.heos.' + this.pid + ".";
              
                      this.log('creating HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
              
                      this.states = [
                          { id: "connected", common: { name: "Verbunden?" } },
                          { id: "command", common: { name: "Befehl an Heos Player senden" } },
                          { id: "ip", common: { name: "IP-Adresse", write: false } },
                          { id: "pid", common: { name: "Player-ID", write: false } },
                          { id: "name", common: { name: "Name des Players", write: false } },
                          { id: "model", common: { name: "Modell des Players", write: false } },
                          { id: "serial", common: { name: "Seriennummer des Players", write: false } },
                          { id: "last_error", common: { name: "Letzte Fehler", write: false } },
                          { id: "volume", common: { name: "Aktuelle Lautstärke" } },
                          { id: "mute", common: { name: "Mute aktiviert?" } },
                          { id: "play_state", common: { name: "Aktueller Wiedergabezustand" } },
                          { id: "play_mode_repeat", common: { name: "Wiedergabewiederholung" } },
                          { id: "play_mode_shuffle", common: { name: "Zufällige Wiedergabe" } },
                          { id: "now_playing_media_type", common: { name: "Aktuelle Wiedergabemedium", write: false } },
                          { id: "now_playing_media_song", common: { name: "Aktuelles Lied", write: false } },
                          { id: "now_playing_media_station", common: { name: "Aktuelle Station", write: false } },
                          { id: "now_playing_media_album", common: { name: "Aktuelle Wiedergabemedium", write: false } },
                          { id: "now_playing_media_artist", common: { name: "Aktueller Artist", write: false } },
                          { id: "now_playing_media_image_url", common: { name: "Aktuelles Coverbild", write: false } },
                          { id: "now_playing_media_album_id", common: { name: "Aktuelle Album-ID", write: false } },
                          { id: "now_playing_media_mid", common: { name: "Aktuelle mid", write: false } },
                          { id: "now_playing_media_qid", common: { name: "Aktuelle qid", write: false } },
                          { id: "cur_pos", common: { name: "lfd. Position" } },
                          { id: "duration", common: { name: "Dauer", write: false } },
                          { id: "cur_pos_MMSS", common: { name: "lfd. Position MM:SS" } },
                          { id: "duration_MMSS", common: { name: "Dauer MM:SS", write: false } },
                          { id: "group_leader", common: { name: "Ist Gruppenleiter", write: false } },
                          { id: "group_member", common: { name: "Ist Gruppenmitglied", write: false } },
                          { id: "group_pid", common: { name: "PlayerIDs in der Gruppe", write: false } },
                          { id: "group_volume", common: { name: "Lautstärke wenn Gruppen-Leiter" } },
                          { id: "group_name", common: { name: "Name der Gruppe", write: false } },
                          { id: "group_mute", common: { name: "Gruppe gemutet?" } },
                          { id: "script_version", common: { name: "Installierte Script-Version", write: false } }
                      ];
                      // beim 1.Start die states erzeugen
                      if (!this.existState("script_version") || this.getState('script_version').val != SCRIPTVERSION) {
                          this.installed = false;
                          this.logWarn('creating HEOS player states for version ' + SCRIPTVERSION + ', please start script again');
                          // states erzeugen
                          for (var s = 0; s < this.states.length; s++) {
                              this.setState(this.states[s].id, "");
                          }
                          this.setState('script_version', SCRIPTVERSION);
                      }
                      else {
                          // Initialisierung der States nach 5 Sek
                          setTimeout(() => {
                              this.setState('ip', this.ip);
                              this.setState('name', this.name);
                              this.setState('pid', this.pid);
                              this.setState('model', this.model);
                              this.setState('serial', this.serial);
                              this.sendCommand('get_play_state|get_play_mode|get_now_playing_media|get_volume');
                          }, 5000);
                          setTimeout(() => {
                              this.startPlayer();
                          }, 10000);
                          this.installed = true;
                      }
                  }
              
                  // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                  // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                  existState(id) {
                      return ($(this.statePath + id).length == 0 ? false : true);
                  }
              
                  // wrapper
                  getState(id) {
                      return getState(this.statePath + id);
                  }
              
                  // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
                  // wenn er noch nicht da ist
                  setState(id, value) {
                      if (!this.existState(id)) this.createState(id, value, undefined);
                      else setState(this.statePath + id, value, true);
                  }
              
                  // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
                  // vorhanden sind (wenn der common-Parameter leer ist)
                  createState(id, value, common) {
                      if (!this.existState(id)) {
                          if (common === undefined) {
                              // id im states-Array suchen
                              for (var i = 0; i < this.states.length; i++) {
                                  if (this.states[i].id == id) {
                                      if (this.states[i].hasOwnProperty('common'))
                                          common = this.states[i].common;
                                      break;
                                  }
                              }
                          }
                          if ((typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                          // unter "0_userdata.0"
                          let obj = {};
                          obj.type = 'state';
                          obj.native = {};
                          obj.common = common;
                          setObject(this.statePath + id, obj, (err) => {
                              if (err) {
                                  this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                              } else {
                                  this.log('state "' + this.statePath + id + '" created');
                              }
                          });
              
                          // value zeitversetzt setzen        
                          setTimeout(setState, 3000, this.statePath + id, value);
                      }
                  }
              
              
                  startPlayer() {
                      try {
                          this.log('starting HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
                          this.onHandler = [];
                          // on-Event für command
                          this.onHandler.push(on({ id: this.statePath + 'command', change: "any" }, (obj) => {
                              this.executeCommand(obj.id, obj.state.val)
                          }));
              
                          // on-Event für volume (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'volume', change: 'ne', ack: false }, (obj) => {
                              this.executeCommand(obj.id, 'set_volume&level=' + obj.state.val);
                          }));
                          // on-Event für mute (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'mute', change: 'ne', ack: false }, (obj) => {
                              this.executeCommand(obj.id, 'set_mute&state=' + (obj.state.val === true ? 'on' : 'off'));
                          }));
                          // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'play_mode_shuffle', change: 'ne', ack: false }, (obj) => {
                              this.executeCommand(obj.id, 'set_play_mode&shuffle=' + (obj.state.val === true ? 'on' : 'off'));
                          }));
                          // on-Event für play_state (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'play_state', change: 'ne', ack: false }, (obj) => {
                              this.executeCommand(obj.id, 'set_play_state&state=' + obj.state.val);
                          }));
              
                          // on-Event für group-volume (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'group_volume', change: 'ne', ack: false }, (obj) => {
                              // "id":"javascript.1.heos.-1746612370.group_volume"
                              var id = obj.id.split('.');
                              this.executeCommand('group/set_volume?gid=' + id[3] + '&level=' + obj.state.val);
                          }));
              
                          // on-Event für group-mute (nur wenn ack=false, also über vis)
                          this.onHandler.push(on({ id: this.statePath + 'group_mute', change: 'ne', ack: false }, (obj) => {
                              // "id":"javascript.1.heos.-1746612370.group_volume"
                              var id = obj.id.split('.');
                              this.heos.executeCommand('group/set_mute?gid=' + id[3] + '&state=' + (obj.state.val === true ? 'on' : 'off'));
                          }));
              
                          this.setState('connected', true);
                      } catch (err) { this.logError('startPlayer: ' + err.message); }
                  }
              
                  // sucht die zur pid passenden player-Insanz
                  executeCommand(objID, cmd) {
                      // aus der objID die pid holen
                      // objID = javascript.1.heos.394645376.command
                      objID = objID.split('.');
                      var pid = objID[3];
                      if (this.pid == pid) {
                          this.sendCommand(cmd);
                      }
                  }
              
                  cleanupNowPlaying(){
                      for (var s = 0; s < this.states.length; s++) {
                          if(this.states[s].id.startsWith("now_playing")){
                              this.setState(this.states[s].id, "");
                          }
                      }
                  }
              
              
                  stopPlayer() {
                      try {
                          this.log('stopping HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
              
                          // events unsubcribe
                          for (let i = 0; i < this.onHandler.length; i++) {
                              if (this.onHandler[i] !== undefined) unsubscribe(this.onHandler[i]);
                          }
                          this.onHandler = [];
                          //cleanup now playing
                          this.cleanupNowPlaying();
                          // reset last error
                          this.setState("last_error", "");
                          // connected zurücksetzen
                          this.setState("connected", false);
                      } catch (err) { this.logError('stopPlayer: ' + err.message); }
                  }
              
                  /** wandelt einen sek Wert in MM:SS Darstellung um
                   **/
                  toMMSS(s) {
                      var sec_num = parseInt(s, 10);
                      var minutes = Math.floor(sec_num / 60);
                      var seconds = sec_num - (minutes * 60);
                      if (seconds < 10) { seconds = "0" + seconds; }
                      return minutes + ':' + seconds;
                  }
              
                  setLastError(err) {
                      try {
                          this.logWarn(err);
                          let val = this.getState('last_error').val + '';
                          let lines = val.split('\n');
                          if (lines.length > 4)
                              lines.pop();
                          lines.unshift(err + '\n');
                          this.setState('last_error', lines.toString());
                      } catch (e) { this.logError('setLastError: ' + e.message); }
                  }
              
              
                  /** Auswertung der empfangenen Daten
                   **/
                  parseResponse(jdata, jmsg, cmd_group, cmd) {
                      try {
                          switch (cmd_group) {
                              case 'event':
                                  switch (cmd) {
                                      case 'player_playback_error':
                                          this.setLastError(jmsg.error.replace(/_/g, ' '));
                                          break;
                                      case 'player_state_changed':
                                          this.setState("play_state", jmsg.state);
                                          this.sendCommand('get_now_playing_media');
                                          break;
                                      case 'player_volume_changed':
                                          this.setState("volume", jmsg.level);
                                          this.setState("mute", (jmsg.mute == 'on' ? true : false));
                                          break;
                                      case 'player_repeat_mode_changed':
                                          this.setState("play_mode_shuffle", jmsg.shuffle);
                                          break;
                                      case 'player_shuffle_mode_changed':
                                          this.setState("play_mode_repeat", jmsg.repeat);
                                          break;
                                      case 'player_now_playing_changed':
                                          this.sendCommand('get_now_playing_media');
                                          break;
                                      case 'player_now_playing_progress':
                                          this.setState("cur_pos", jmsg.cur_pos / 1000);
                                          this.setState("cur_pos_MMSS", this.toMMSS(jmsg.cur_pos / 1000));
                                          this.setState("duration", jmsg.duration / 1000);
                                          this.setState("duration_MMSS", this.toMMSS(jmsg.duration / 1000));
                                          break;
                                  }
                                  break;
              
              
                              case 'player':
                                  switch (cmd) {
                                      case 'set_volume':
                                      case 'get_volume':
                                          if (getState(this.statePath + "volume").val != jmsg.level)
                                              this.setState("volume", jmsg.level);
                                          break;
                                      case 'set_mute':
                                      case 'get_mute':
                                          this.setState("mute", (jmsg.state == 'on' ? true : false));
                                          break;
                                      case 'set_play_state':
                                      case 'get_play_state':
                                          this.setState("play_state", jmsg.state);
                                          break;
                                      case 'set_play_mode':
                                      case 'get_play_mode':
                                          this.setState("play_mode_repeat", jmsg.repeat);
                                          this.setState("play_mode_shuffle", (jmsg.shuffle == 'on' ? true : false));
                                          break;
                                      case 'get_now_playing_media':
                                          this.setState("now_playing_media_type", jdata.payload.type);
                                          if (jdata.payload.hasOwnProperty('song'))
                                              this.setState("now_playing_media_song", jdata.payload.song);
                                          if (jdata.payload.hasOwnProperty('album'))
                                              this.setState("now_playing_media_album", jdata.payload.album);
                                          if (jdata.payload.hasOwnProperty('album_id'))
                                              this.setState("now_playing_media_album_id", jdata.payload.album_id);
                                          if (jdata.payload.hasOwnProperty('artist'))
                                              this.setState("now_playing_media_artist", jdata.payload.artist);
                                          if (jdata.payload.hasOwnProperty('image_url'))
                                              this.setState("now_playing_media_image_url", jdata.payload.image_url);
                                          if (jdata.payload.hasOwnProperty('mid'))
                                              this.setState("now_playing_media_mid", jdata.payload.mid);
                                          if (jdata.payload.hasOwnProperty('qid'))
                                              this.setState("now_playing_media_qid", jdata.payload.qid);
                                          if (jdata.payload.hasOwnProperty('type')) {
                                              if (jdata.payload.type == 'station') {
                                                  this.setState("now_playing_media_station", jdata.payload.station);
                                              } else {
                                                  this.setState("now_playing_media_station", "");
                                              }
                                          }
                                          break;
                                  }
                                  break;
                          } // switch
              
              
                      } catch (err) { this.logError('parseResponse: ' + err.message); }
                  }
              
                  /** cmd der Form "cmd&param"  werden zur msg heos+cmd+pid+&param aufbereitet
                      cmd der Form "cmd?param"  werden zur msg heos+cmd+?param aufbereitet
                   **/
                  commandToMsg(cmd) {
                      var param = cmd.split('&');
                      cmd = param[0];
                      if (param.length > 1) param = '&' + param[1]; else param = '';
                      var cmd_group = 'player';
              
                      switch (cmd) {
                          case 'get_play_state':
                          case 'get_play_mode':
                          case 'get_now_playing_media':
                          case 'get_volume':
                          case 'play_next':
                          case 'play_previous':
                          case 'set_mute':       // &state=on|off        
                          case 'set_volume':     // &level=1..100   
                          case 'volume_down':    // &step=1..10   
                          case 'volume_up':      // &step=1..10
                          case 'set_play_state': // &state=play|pause|stop
                          case 'set_play_mode':  // &repeat=on_all|on_one|off  shuffle=on|off
                              break;
              
                          // browse            
                          case 'play_preset':    // heos://browse/play_preset?pid=player_id&preset=preset_position
                              cmd_group = 'browse';
                              break;
                          case 'play_stream':    // heos://browse/play_stream?pid=player_id&url=url_path
                              cmd_group = 'browse';
                              break;
              
                      }
                      return 'heos://' + cmd_group + '/' + cmd + '?pid=' + this.pid + param;
                  }
              
                  /** Nachricht (command) an player senden
                      es sind auch mehrere commands, getrennt mit | erlaubt
                      bsp: set_volume&level=20|play_preset&preset=1
                   **/
                  sendCommand(command) {
                      if (!this.installed) return;
              
                      var cmds = command.split('|');
                      for (var c = 0; c < cmds.length; c++) {
                          this.heos.msgs.push(this.commandToMsg(cmds[c]));
                      }
                      this.heos.sendNextMsg();
                  }
              
              
              } // end of HeosPlayer
              
              
              /* -----
                 Heos
                 ----- */
              // Heos Instanz erzeugen und verbinden   
              var heos = new Heos();
              heos.connect();
              
              // wenn das Script beendet wird, dann auch die Heos Instanz beenden
              onStop(function () {
                  heos.disconnect();
              }, 0);
              
              UhulaU 1 Antwort Letzte Antwort
              0
              • W withstu

                @Brati Ja ich habe grad auch wieder Probleme mich einzuloggen...

                @Uhula Ich habe in den letzten Tagen noch ein paar Bugs gefixt und das get_players Verhalten umgestellt. Jetzt werden einzelne Player disconnected und nicht mehr alle.

                /****************************
                ### HEOS Script for ioBroker
                
                #### Funktion
                
                Das Script stellt zwei JS Klassen zur Steuerung der Denon HEOS Geräte zur Verfügung. Die class Heos dient dabei dem Erkennen und Steuern der HEOS Geräte. Die class HeosPlayer dient der Interpretation der Antworten der Heos Geräte.
                 
                Das Script muss lediglich gestartet werden, es sucht dann im Netzwerk nach HEOS Playern und erzeugt in der aktuellen Javascript-Instanz einen Subeintrag für die Favoriten und je einen Subeintrag für jeden gefundenen Player. Dort wiederum werden State-Variablen zur Aufnahme der Player-Daten angelegt.
                 
                Das Script erzeugt auch on-Handler um auf Steuerungen über vis und andere Scripte an den State-Variablen reagieren zu können.
                 
                Beim Beenden des Scripts werden alle Verbindungen und on-Handler geschlossen.
                
                Das Script ermöglicht die HEOS Player zu steuern, es soll aber nicht die HEOS App ersetzen. 
                 
                  
                #### Wichtig!
                
                * Im Javascript-Adapter muss in der Instanz-Konfiguration "node-ssdp" mit angegeben werden! Alternativ kann die Bibliothek auch komplett über "npm install node-ssdp" installiert werden.
                * Wenn mit Favoriten (Presets) gearbeitet werden soll, müssen die HEOS-Konto Logindaten in den beiden Konstanten HEOS_USERNAME (EmailAdr) und HEOS_PASSWORD hier im Script in der Konfiguration angegeben werden (so, wie in der HEOS App)!
                * Eine Konfiguration von IP-Adressen und Player-IDs ist nicht notwendig!
                * U.U. kann es notwendig sein das Script nach dem 1.Start zu beenden und nach 30 Sek erneut zu starten, da die Neuanlage der ioBroker States etwas Zeit benötigt. Warnungen sind dabei zu ignorieren. ;-)
                
                #### Updates
                 
                ##### v2.0 13.03.2020
                * das Script überprüft nun, ob alle notwendigen states für Heos und HeosPlayer im ioBroker korrekt erzeugt wurden und gibt eine Warnung mit Script-Neustartaufforderung aus, wenn die states nicht vorhanden sind. Dieses ist notwendig, da das Anlegen von states asynchron erfolgt und einige ms dauern kann
                * (WICHTIG!) die states werden nicht mehr in der aktuellen Javascript-Instanz und auch nicht mehr unter der IP des Heos-Players gespeichert, sondern Javascript-Instanzunabhängig unter 0_userdata.0 und seiner Player-ID (pid), da diese sich nicht ändert. Die IP hingegen u.U. schon. Also statt "javascript.X.heos.192_168_2_43" nun als "0_userdata.0.heos.12345678". Wer bereits auf die alten Werte im VIS zugreift, muss dieses im VIS anpassen!  
                * es wurden Befehle/states für die Gruppensteuerung der Heos-Player hinzugefügt. Beim Start werden die Gruppen ausgelesen und in den Player-states des Gruppenleiters (der erste genannte Player) gespeichert. Über dessen states kann die Gruppe gesteuert werden: 
                    group_volume: dient der Steuerung der Gruppen-Lautstärke
                    group_mute: dient der Steuerung der Gruppen-Mutes
                    group_leader: ist true, wenn der Player der Gruppenleiter ist
                    group_member: ist true, wenn der Player Mitglied einer Gruppe ist
                * alle 60 Sek wird überprüft, ob noch alle HEOS-Player erreichbar sind bzw. neue/reconnectete hinzugekommen sind. Neue/reconnectete werden der Liste der HEOS-Player hinzugefügt, fehlende werden gestoppt. Da hierzu das HEOS-Netzwerk gefragt wird (get_players Meldung), kann es bis zu 5 Min dauern bis Änderungen erkannt werden. Der neue HEOS-Player-State "connected" wird entsprechend gesetzt
                * jeder HEOS-Player hat einen neuen state "connected", dieser wird nach erfolgreichem Start auf true gesetzt, bei korrektem Beenden des Scripts auf false
                * diverse Filter/Korrekturen aus dem Forum übernommen, vielen dank an withstu
                  
                  
                 #### class Heos
                 
                 Diese Basisklasse dient 
                
                * dem Erkennen von HEOS Geräten (Playern). Das Erkennen der HEOS Geräte findet via UPD unter Nutzung von node-ssdp statt. node-ssdp muss dazu im Javascript-Adapter in der Konfiguration mit angegeben werden!
                * der Kommunikation über TelNet. Es wird genau eine TelNet Verbindung zu einem HEOS Gerät aufgebaut, dieses reicht die Sendungen und Antworten zentral weiter
                * der Ermittlung von Favoriten (Presets). Für jeden Favorit wird ein ioBroker State heos.presets.n mit entsprechenden Sub-States erzeugt. Zur Nutzung der Presets ist ein SignIn notwendig, hierzu müssen HEOS_USERNAME und HEOS_PASSWORD gesetzt werden.
                * dem Instanziieren der class HeosPlayer je HEOS Gerät. Je HEOS Gerät wird ein ioBroker-State mit der IP-Adresse des Players erzeugt, dieser State erhält diverse Sub-States
                  
                ##### State-Variable: Heos
                 
                Werden angelegt unter "0_userdata.0.heos."
                
                * connected: true wenn die Verbindung zu mindestens einem HEOS-Player besteht
                * script_version: Version des Scripts, dient dazu Script-Updates zu erkennen
                * last_error: Letzter Fehlertext
                * command(cmd): Hierüber können der Heos-Klasse Befehle übergeben werden, für cmd gilt:
                    "connect": Verbindung zu HEOS aufbauen bzw. erneut aufbauen (praktisch ein reset)
                    "disconnect": Verbindung zu HEOS beenden
                    "load_presets": lädt die Favoriten neu
                  
                    "group/set_group?pid=<pid1>,<pid2>,...": setzen einer Gruppe, die pids sind die der Player wie sie unter den Objekten für jeden Player abgelegt sind. Bsp: "group/set_group?pid=12345678,12345679". 
                 
                   "group/set_group?pid=<pid1>" : hebt die Gruppierung des Players mit der pid1 wieder auf. Bsp: "group/set_group?pid=12345678"
                   "...": alle anderen cmd-Werte werden "as is" versucht an HEOS zu senden
                 
                  
                * presets.<n>: Hierunter werden die Favoriten, Presets angelegt. Je Favorit ein Unterordner n=1 bis Anzahl. Darunter befinden sich dann die States, welche den Inhalt der Favoriten aufnehmen:
                 
                * image_url (read): Bild des Favoriten 
                * name (read): Name des Favoriten
                * playable (read): Spielbar? true/false
                * type (read): Typ des Favoriten (station, ...)
                 
                    
                   
                 #### class HeosPlayer 
                 
                 Diese Klasse dient
                * der Steuerung genau eines HEOS Gerätes. Hierzu wird die zentrale Telnet Verbindung der class Heos genutzt.
                * dem Erzeugen der ioBroker-States zum Speichern der Geräte-Werte
                * der Auswertung von Antworten der HEOS Geräte und Zuweisung an die entsprechenden ioBroker-States
                 
                ##### State-Variable
                
                Werden angelegt unter "0_userdata.0.heos.<pid>"
                
                * connected : true, wenn eine Verbindung besteht, sonst false
                * command(cmd): Hierüber können dem Heos-Player Befehle übergeben werden. Diese werden im Klartext in die State-Variable geschrieben. Getrennt durch das | Zeichen können mehrere hintereinander eingetragen werden. Bsp: Setzen der Lautstärke auf 20 und Abspielen des 1.Favoriten "set_volume&level=20|play_preset&preset=1|set_play_state&state=play". Folgende cmd sind erlaubt:
                
                  "set_volume&level=0|1|..|100" : Setzt die gewünschte Lautstärke 
                  "set_play_state&state=play|pause|stop" : Startet und stoppt die Wiedergabe
                  "set_play_mode&repeat=on_all|on_one|off&shuffle=on|off": Setzt Wiederholung und Zufallsweidergabe
                  "set_mute&state=on|off" : Stumm schalten oder nicht
                  "volume_down&step=1..10" : Lautstärke verringern um   
                  "volume_up&step=1..10"  : Lauststäre erhöhen um
                  "play_next"  : Nächsten Titel spielen
                  "play_previous" : Vorherigen Titel spielen
                  "play_preset&preset=1|2|..|n" : Favorit Nr n abspielen
                  "play_stream&url=url_path" : URL-Stream abspielen
                 
                * cur_pos (read) : lfd. Position der Wiedergabe in [Sek]
                * cur_pos_MMSS (read) : lfd. Position der Wiedergabe im Format MM:SS
                * duration (read) : Länge des aktuellen Titels in [Sek]
                * duration_MMSS (read) : Länge des aktuellen Titels im Format MM:SS
                * ip (read): IP-Adresse des HEOS Players
                * last_error (read): Text des letzten Fehlers, der vom Player gesendet wurde. Wird bei jedem neuen Befehl zurückgesetzt. Wenn man bspw. versucht eine Wiedergabe über Amazon o.ä. zu starten und es gibt aber keine Verbindung dahin, steht hier der Fehlertext drin
                * model (read): Modell des HEOS Players
                * mute (read write): Boolsche Variable, die anzeigt ob der Player gemutet (Stumm geschaltet) wurde. Hierüber kann auch ein mute gesetzt werden
                * name (read): Name des HEOS Players
                * now_playing_media_... (read) : Eine Gruppe von States, in welchen Infos über den aktuellen Titel gespeichert werden, wird automatisch aktualisiert. 
                * pid (read): Player-ID des HEOS Players
                * play_mode_repeat (read write) : Repeat-Modus der Wiedergabe. Mögliche Werte: on_all|on_one|off  
                * play_mode_shuffle (read write) : Zufallswiedergabe true/false
                * play_state (read write): Zustand des Players. Mögliche Werte play|pause|stop
                * serial (read): Seriennummmer des HEOS Players
                * volume (read write): Lautstärke im Bereich 0 - 100. 
                * group_leader : Ist Gruppenleiter
                * group_member : Ist Gruppenmitglied
                * group_pid : Player pids in der Gruppe
                * group_volume : Lautstärke wenn Gruppen-Leiter
                * group_name : Name der Gruppe
                * group_mute : Gruppe gemutet?
                
                 
                #### Weiterführende Links
                
                * HEOS CLI Protokoll: http://rn.dmglobal.com/euheos/HEOS_CLI_ProtocolSpecification.pdf
                * http://forum.iobroker.net/viewtopic.php?f=30&t=5693&p=115554#p115554
                 
                 
                (c) Uhula, MIT License, no warranty, use on your own risc
                 
                */
                
                /****************************
                 * Konfiguration
                 ****************************/
                
                const HEOS_USERNAME = '';
                const HEOS_PASSWORD = '';
                
                const HEARTBEAT_INTERVAL = 15000;
                const HEARTBEAT_TIMEOUT = 60000;
                
                
                /****************************
                 * ab hier nichts mehr ändern ;-) 
                 ****************************/
                
                var net = require('net');
                
                const stateDISCONNECTED = 0;
                const stateSEARCHING = 1;
                const stateCONNECTING = 2;
                const stateCONNECTED = 3;
                const SCRIPTVERSION = '2.0/2020-03-21';
                
                /********************
                 * class Heos
                 ********************/
                class Heos {
                
                    logDebug(msg) { console.debug('[Heos] ' + msg); }
                    log(msg) { console.log('[Heos] ' + msg); }
                    logWarn(msg) { console.warn('[Heos] ' + msg); }
                    logError(msg) { console.error('[Heos] ' + msg); }
                
                    constructor() {
                        this.init();
                        this.states = [
                            { id: "command", common: { name: "Kommando für HEOS Aufrufe" } },
                            { id: "connected", common: { name: "Verbunden?", write: false, def: false } },
                            { id: "last_error", common: { name: "Letzte Fehler", write: false } },
                            { id: "script_version", common: { name: "Installierte Script-Version", write: false } }
                        ];
                        // beim 1.Start nur die States erzeugen
                        if (!this.existState("script_version") || (this.getState('script_version').val != SCRIPTVERSION)) {
                            this.installed = false;
                            this.logWarn('creating HEOS states for version ' + SCRIPTVERSION + ', please start script again');
                            // Anlage der States 
                            for (var s = 0; s < this.states.length; s++) {
                                this.setState(this.states[s].id);
                            }
                            this.setState('script_version', SCRIPTVERSION);
                        }
                        else {
                            this.installed = true;
                            on({ id: this.statePath + 'command', change: "any" }, (obj) => {
                                this.executeCommand(obj.state.val);
                            });
                        }
                    }
                
                
                
                    // Initialisierung
                    init() {
                        this.statePath = '0_userdata.0.heos.';
                        this.players = {};
                        this.heartbeatInterval = undefined;
                        this.heartbeatTimeout = undefined;
                        this.ssdpSearchInterval = undefined;
                        this.net_client = undefined;
                        this.nodessdp_client = undefined;
                
                        this.ip = '';
                        this.msgs = [];
                        this.lastResponse = '';
                        this.state = stateDISCONNECTED;
                        this.unfinishedResponses = '';
                        this.ssdpSearchTargetName = 'urn:schemas-denon-com:device:ACT-Denon:1';
                    }
                
                
                    // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                    // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                    existState(id) {
                        return ($(this.statePath + id).length == 0 ? false : true);
                    }
                
                    // wrapper
                    getState(id) {
                        return getState(this.statePath + id);
                    }
                
                    // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
                    // wenn er noch nicht da ist
                    setState(id, value) {
                        if (!this.existState(id)) this.createState(id, value, undefined);
                        else setState(this.statePath + id, value, true);
                    }
                
                    // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
                    // vorhanden sind (wenn der common-Parameter leer ist)
                    createState(id, value, common) {
                        if (!this.existState(id)) {
                            if (common === undefined) {
                                // id im states-Array suchen
                                for (var i = 0; i < this.states.length; i++) {
                                    if (this.states[i].id == id) {
                                        if (this.states[i].hasOwnProperty('common'))
                                            common = this.states[i].common;
                                        break;
                                    }
                                }
                            }
                            if ((typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                            // unter "0_userdata.0"
                            let obj = {};
                            obj.type = 'state';
                            obj.native = {};
                            obj.common = common;
                            setObject(this.statePath + id, obj, (err) => {
                                if (err) {
                                    this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                                } else {
                                    this.log('state "' + this.statePath + id + '" created');
                                }
                            });
                
                            // value zeitversetzt setzen        
                            setTimeout(setState, 3000, this.statePath + id, value);
                        }
                    }
                
                    /** Verbindung zum HEOS System herstellen
                     **/
                    connect() {
                        if (!this.installed) return;
                
                        try {
                            this.log("searching for HEOS devices ...")
                            this.setState("connected", false);
                            this.state = stateSEARCHING;
                            const NodeSSDP = require('node-ssdp').Client;
                            this.nodessdp_client = new NodeSSDP();
                            this.nodessdp_client.explicitSocketBind = true;
                            this.nodessdp_client.on('response', (headers, statusCode, rinfo) => this.onNodeSSDPResponse(headers, statusCode, rinfo));
                            this.nodessdp_client.on('error', error => { this.nodessdp_client.close(); this.logError(error); });
                            this.nodessdp_client.search(this.ssdpSearchTargetName);
                            this.ssdpSearchInterval = setInterval(() => {
                                this.log("still searching for HEOS devices ...")
                                this.nodessdp_client.search(this.ssdpSearchTargetName);
                            }, 30000);
                        } catch (err) { this.logError('connect: ' + err.message); }
                
                    }
                
                    /** Alle Player stoppen und die TelNet Verbindung schließen 
                     **/
                    disconnect() {
                        this.log('disconnecting from HEOS ...');
                        unsubscribe(this.statePath.substr(0, this.statePath.length - 1));
                
                        this.stopHeartbeat();
                        this.stopPlayers();
                
                        if (typeof this.net_client !== 'undefined') {
                            this.registerChangeEvents(false);
                            this.net_client.destroy();
                            this.net_client.unref();
                        }
                        if (typeof this.nodessdp_client !== 'undefined') {
                            this.nodessdp_client.stop();
                        }
                        this.setState("connected", false);
                        this.state = stateDISCONNECTED;
                        this.log('disconnected from HEOS');
                    }
                
                    reconnect() {
                        if (this.state == stateCONNECTED) {
                            this.log('reconnecting to HEOS ...');
                            this.disconnect();
                            setTimeout(() => {
                                this.init();
                                this.connect();
                            }, 5000);
                        }
                    }
                
                    executeCommand(cmd) {
                        //l('command: '+cmd);
                        switch (cmd) {
                            case 'load_presets':
                                this.getMusicSources();
                                break;
                            case 'group/get_groups':
                                this.getGroups();
                                break;
                            case 'connect':
                                this.disconnect();
                                this.init();
                                this.connect();
                                break;
                            case 'disconnect':
                                this.disconnect();
                                break;
                            default:
                                if (this.state == stateCONNECTED) {
                                    this.msgs.push('heos://' + cmd + '\n');
                                    this.sendNextMsg();
                                }
                
                        }
                    }
                    /** es wurde mindestens ein Player erkannt, nun über dessen IP alle bekannten HEOS Player
                     *  durch senden von "player/get_players" ermitteln
                     */
                    onNodeSSDPResponse(headers, statusCode, rinfo) {
                        try {
                            // rinfo {"address":"192.168.2.225","family":"IPv4","port":53871,"size":430}
                            if (typeof this.net_client == 'undefined') {
                                if (headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                                    this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
                                } else {
                                    if (this.ssdpSearchInterval) {
                                        clearInterval(this.ssdpSearchInterval);
                                        this.ssdpSearchInterval = undefined;
                                    }
                
                                    this.ip = rinfo.address;
                                    this.log('connecting to HEOS (' + this.ip + ') ...');
                                    this.net_client = net.connect({ host: this.ip, port: 1255 });
                                    this.net_client.setKeepAlive(true, 5000);
                                    this.net_client.setNoDelay(true);
                                    this.net_client.setTimeout(15000);
                
                                    this.state = stateCONNECTING;
                
                                    this.net_client.on('error', (error) => {
                                        this.logError(error);
                                        this.reconnect();
                                    });
                
                                    this.net_client.on('connect', () => {
                                        this.setState("connected", true);
                                        this.state = stateCONNECTED;
                                        this.log('connected to HEOS (' + this.ip + ')');
                                        this.getPlayers();
                                        this.registerChangeEvents(true);
                                        this.signIn();
                                        this.getMusicSources();
                                        this.getGroups();
                                        this.startHeartbeat();
                                    });
                
                                    // Gegenseite hat die Verbindung geschlossen 
                                    this.net_client.on('end', () => {
                                        this.logWarn('HEOS closed the connection to ' + this.ip);
                                        this.reconnect();
                                    });
                
                                    // timeout
                                    this.net_client.on('timeout', () => {
                                        this.logWarn('Timeout trying connect to ' + this.ip);
                                        this.reconnect();
                                    });
                
                                    // Datenempfang
                                    this.net_client.on('data', (data) => this.onData(data));
                                }
                            }
                        } catch (err) { this.logError('onNodeSSDPResponse: ' + err.message); }
                    }
                
                    setLastError(err) {
                        this.logWarn(err);
                        let val = this.getState('last_error').val + '';
                        let lines = val.split('\n');
                        if (lines.length > 4)
                            lines.pop();
                        lines.unshift(err + '\n');
                        this.setState('last_error', lines.toString());
                    }
                
                
                    /** es liegen Antwort(en) vor
                     * 
                     * {"heos": {"command": "browse/browse", "result": "success", "message": "sid=1028&returned=9&count=9"}, 
                     *    "payload": [
                     *        {"container": "no", "mid": "s25529", "type": "station", "playable": "yes", "name": "NDR 1 Niedersachsen (Adult Hits)", "image_url": "http://cdn-profiles.tunein.com/s25529/images/logoq.png?t=154228"}, 
                     *        {"container": "no", "mid": "s56857", "type": "station", "playable": "yes", "name": "NDR 2 Niedersachsen 96.2 (Top 40 %26 Pop Music)", "image_url": "http://cdn-profiles.tunein.com/s56857/images/logoq.png?t=154228"}, 
                     *        {"container": "no", "mid": "s24885", "type": "station", "playable": "yes", "name": "NDR Info", "image_url": "http://cdn-profiles.tunein.com/s24885/images/logoq.png?t=1"}, {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
                     *        {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}, 
                     *        {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
                     *        {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk"
                     **/
                    onData(data) {
                        try {
                            data = data.toString();
                            data = data.replace(/[\n\r]/g, '');    // Steuerzeichen "CR" entfernen   
                            // es können auch mehrere Antworten vorhanden sein! {"heos": ... } {"heos": ... }
                            // diese nun in einzelne Antworten zerlegen
                            data = this.unfinishedResponses + data;
                            this.unfinishedResponses = '';
                
                            data = data.replace(/{"heos":/g, '|{"heos":');
                            var responses = data.split('|');
                            responses.shift();
                            for (var r = 0; r < responses.length; r++) if (responses[r].trim().length > 0) {
                                try {
                                    JSON.parse(responses[r]); // check ob korrektes JSON Array
                                    this.parseResponse(responses[r]);
                                } catch (e) {
                                    this.logDebug('onData: invalid json (error: ' + e.message + '): ' + responses[r]);
                                    this.unfinishedResponses += responses[r];
                                }
                            }
                            // wenn weitere Msg zum Senden vorhanden sind, die nächste senden
                            if (this.msgs.length > 0)
                                this.sendNextMsg();
                        } catch (err) { this.logError('onData: ' + err.message); }
                    }
                
                    /** Antwort(en) verarbeiten. Sich wiederholende Antworten ignorieren
                     **/
                    parseResponse(response) {
                        try {
                            this.logDebug('parseResponse: ' + response);
                
                            if (response == this.lastResponse || response.indexOf("command under process") > 0)
                                return
                            this.lastResponse = response;
                
                            var jmsg;
                            var i;
                            var jdata = JSON.parse(response);
                            if (!jdata.hasOwnProperty('heos') || !jdata.heos.hasOwnProperty('command'))
                                return;
                
                            // msg auswerten
                            try {
                                jmsg = '{"' + decodeURI(jdata.heos.message).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"').replace(/\s/g, '_') + '"}';
                                jmsg = JSON.parse(jmsg);
                            } catch (err) {
                                jmsg = {};
                            }
                
                            // result ?
                            var result = 'success';
                            if (jdata.heos.hasOwnProperty('result')) result = jdata.heos.result;
                            if (result != 'success') {
                                this.setLastError('result=' + result + ', ' + jmsg.text);
                            }
                
                            // cmd auswerten
                            var cmd = jdata.heos.command.split('/');
                            var cmd_group = cmd[0];
                            cmd = cmd[1];
                            switch (cmd_group) {
                                case 'system':
                                    switch (cmd) {
                                        case 'heart_beat':
                                            this.resetHeartbeatTimeout();
                                            break;
                                    }
                                    break;
                                case 'event':
                                    switch (cmd) {
                                        case 'players_changed':
                                            this.getPlayers();
                                            break;
                                        case 'groups_changed':
                                            this.getGroups();
                                            break;
                                        case 'group_volume_changed':
                                            // "heos": {"command": "event/group_volume_changed ","message": "gid='group_id'&level='vol_level'&mute='on_or_off'"}
                                            if (jmsg.hasOwnProperty('gid')) {
                                                if (jmsg.hasOwnProperty('level')) {
                                                    this.setState(jmsg.gid + '.group_volume', jmsg.level);
                                                }
                                                if (jmsg.hasOwnProperty('mute')) {
                                                    this.setState(jmsg.gid + '.group_mute', (jmsg.mute == 'on' ? true : false));
                                                }
                                            }
                                            break;
                                    }
                                    break;
                                case 'player':
                                    switch (cmd) {
                                        // {"heos": {"command": "player/get_players", "result": "success", "message": ""}, 
                                        //  "payload": [{"name": "HEOS Bar", "pid": 1262037998, "model": "HEOS Bar", "version": "1.430.160", "ip": "192.168.2.225", "network": "wifi", "lineout": 0, "serial": "ADAG9170202780"}, 
                                        //              {"name": "HEOS 1 rechts", "pid": -1746612370, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.201", "network": "wifi", "lineout": 0, "serial": "AMWG9170934429"}, 
                                        //              {"name": "HEOS 1 links", "pid": 68572158, "model": "HEOS 1", "version": "1.430.160", "ip": "192.168.2.219", "network": "wifi", "lineout": 0, "serial": "AMWG9170934433"}
                                        //             ]}
                                        case 'get_players':
                                            if (jdata.hasOwnProperty('payload')) {
                                                this.startPlayers(jdata.payload);
                                            }
                                            break;
                                    }
                                    break;
                
                                // {"heos": {"command": "browse/get_music_sources", "result": "success", "message": ""}, 
                                //  "payload": [{"name": "Amazon", "image_url": "https://production...png", "type": "music_service", "sid": 13}, 
                                //              {"name": "TuneIn", "image_url": "https://production...png", "type": "music_service", "sid": 3}, 
                                //              {"name": "Local Music", "image_url": "https://production...png", "type": "heos_server", "sid": 1024}, 
                                //              {"name": "Playlists", "image_url": "https://production...png", "type": "heos_service", "sid": 1025}, 
                                //              {"name": "History", "image_url": "https://production...png", "type": "heos_service", "sid": 1026}, 
                                //              {"name": "AUX Input", "image_url": "https://production...png", "type": "heos_service", "sid": 1027}, 
                                //              {"name": "Favorites", "image_url": "https://production...png", "type": "heos_service", "sid": 1028}]}
                                case 'browse':
                                    switch (cmd) {
                                        case 'get_music_sources':
                                            if ((jdata.hasOwnProperty('payload'))) {
                                                for (i = 0; i < jdata.payload.length; i++) {
                                                    var source = jdata.payload[i];
                                                    if (source.name == 'Favorites') {
                                                        this.browse(source.sid);
                                                    }
                                                }
                                            }
                
                                            break;
                
                                        // {"heos": {"command": "browse/browse", "result": "success", "message": "pid=1262037998&sid=1028&returned=5&count=5"}, 
                                        //  "payload": [{"container": "no", "mid": "s17492", "type": "station", "playable": "yes", "name": "NDR 2 (Adult Contemporary Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s17492q.png"}, 
                                        //              {"container": "no", "mid": "s158432", "type": "station", "playable": "yes", "name": "Absolut relax (Easy Listening Music)", "image_url": "http://cdn-radiotime-logos.tunein.com/s158432q.png"}, 
                                        //              {"container": "no", "mid": "catalog/stations/A1W7U8U71CGE50/#chunk", "type": "station", "playable": "yes", "name": "Ed Sheeran", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/EdSheeran._SX200_SY200_.jpg"}, 
                                        //              {"container": "no", "mid": "catalog/stations/A1O1J39JGVQ9U1/#chunk", "type": "station", "playable": "yes", "name": "Passenger", "image_url": "https://images-na.ssl-images-amazon.com/images/I/71DsYkU4QaL._SY500_CR150,0,488,488_SX200_SY200_.jpg"}, 
                                        //              {"container": "no", "mid": "catalog/stations/A316JYMKQTS45I/#chunk", "type": "station", "playable": "yes", "name": "Johannes Oerding", "image_url": "https://images-na.ssl-images-amazon.com/images/G/01/Gotham/DE_artist/JohannesOerding._SX200_SY200_.jpg"}], 
                                        //  "options": [{"browse": [{"id": 20, "name": "Remove from HEOS Favorites"}]}]}                    
                                        case 'browse':
                                            if ((jdata.hasOwnProperty('payload'))) {
                                                for (i = 0; i < jdata.payload.length; i++) {
                                                    var preset = jdata.payload[i];
                                                    this.createState('presets.' + (i + 1) + '.name', preset.name, { name: 'Favoritenname ' });
                                                    this.createState('presets.' + (i + 1) + '.playable', (preset.playable == 'yes' ? true : false), { name: 'Favorit ist spielbar' });
                                                    this.createState('presets.' + (i + 1) + '.type', preset.type, { name: 'Favorittyp' });
                                                    this.createState('presets.' + (i + 1) + '.image_url', preset.image_url, { name: 'Favoritbild' });
                                                }
                                            }
                                            break;
                                    }
                                    break;
                
                                case 'group':
                                    //l('group: '+response);
                                    switch (cmd) {
                                        // { "heos":{"command":"player/set_group","result":"success",
                                        //           "message": "gid='new group_id'&name='group_name'&pid='player_id_1, player_id_2,…,player_id_n'
                                        //          } 
                                        // }
                                        case 'set_group':
                                            this.setGroup(jmsg);
                                            break;
                
                                        // { "heos": {"command":"group/get_volume","result":"success","message": "gid='group_id'&level='vol_level'"}
                                        case 'get_volume':
                                            if (jmsg.hasOwnProperty('gid')) {
                                                if (jmsg.hasOwnProperty('level')) {
                                                    this.setState(jmsg.gid + '.group_volume', jmsg.level);
                                                }
                                            }
                                            break;
                
                                        // { "heos": {"command":"group/get_mute","result":"success","message": "gid='group_id'&state='on_or_off'"}
                                        case 'get_mute':
                                            if (jmsg.hasOwnProperty('gid')) {
                                                if (jmsg.hasOwnProperty('state')) {
                                                    this.setState(jmsg.gid + '.group_mute', (jmsg.state == 'on' ? true : false));
                                                }
                                            }
                                            break;
                
                
                                        // { "heos": { "command": "player/get_groups", "result": "success", "message": "" },
                                        //   "payload": [{"name":"'group name 1'", "gid": "group id 1'",
                                        //                "players":[{"name":"player name 1","pid":"'player id1'","role":"player role 1 (leader or member)'"},
                                        //                           {"name":"player name 2","pid":"'player id2'","role":"player role 2 (leader or member)'"} 
                                        //                          ]
                                        //               },
                                        //               {"name":"'group name 2'","gid":"group id 2'",
                                        //                "players":[{"name":"player name ... 
                                        case 'get_groups':
                                            // bisherige groups leeren
                                            var objs = $(this.statePath + '*.group_name');
                                            for (var o = 0; o < objs.length; o++) setState(objs[o], 'no group');
                                            objs = $(this.statePath + '*.group_leader');
                                            for (var o = 0; o < objs.length; o++) setState(objs[o], false);
                                            objs = $(this.statePath + '*.group_member');
                                            for (var o = 0; o < objs.length; o++) setState(objs[o], false);
                                            objs = $(this.statePath + '*.group_pid');
                                            for (var o = 0; o < objs.length; o++) setState(objs[o], '');
                
                                            // payload mit den groups auswerten
                                            if ((jdata.hasOwnProperty('payload'))) {
                                                for (i = 0; i < jdata.payload.length; i++) {
                                                    var group = jdata.payload[i];
                                                    var players = group.players;
                                                    // Player IDs addieren. Hinweis: "leader" ist nicht immer der 1.Playereintrag
                                                    group.pid = "";
                                                    for (var p = 0; p < players.length; p++) {
                                                        if (players[p].role == 'leader')
                                                            group.pid = players[p].pid + (group.pid.length > 0 ? "," : "") + group.pid;
                                                        else
                                                            group.pid = group.pid + (group.pid.length > 0 ? "," : "") + players[p].pid;
                                                    }
                                                    this.setGroup(group);
                                                }
                                            }
                                            break;
                
                                    }
                                    break;
                
                
                                case 'system':
                                    switch (cmd) {
                                        case 'sign_in':
                                            this.log('signed in: ' + jdata.heos.result);
                                            break;
                                    }
                                    break;
                            }
                
                
                            // an die zugehörigen Player weiterleiten
                            if (jmsg.hasOwnProperty('pid')) {
                                if(jmsg.pid in this.players){
                                    this.players[jmsg.pid].parseResponse(jdata, jmsg, cmd_group, cmd);
                                }
                            }
                
                
                        } catch (err) { this.logError('parseResponse: ' + err.message + '\n ' + response); }
                    }
                
                
                    // sucht die zur pid passenden player-Insanz
                    sendCommandToPlayer(objID, cmd) {
                        // aus der objID die pid holen
                        // objID = javascript.1.heos.394645376.command
                        objID = objID.split('.');
                        var pid = objID[3];
                        if(pid in this.players){
                            this.players[pid].sendCommand(cmd);
                        }
                    }
                
                    stopPlayer(pid){
                        try {
                            let heosPlayer = this.players[pid];
                            if (heosPlayer)
                                heosPlayer.stopPlayer();
                            // player leeren
                            delete this.players[pid];
                        } catch (err) { this.logError('stopPlayer: ' + err.message); }
                    }
                
                    // Für die gefundenen HEOS Player entsprechende class HeosPlayer Instanzen bilden und nicht mehr verbundene Player stoppen
                    startPlayers(payload) {
                        try {
                            var connectedPlayers = [];
                            for (var i = 0; i < payload.length; i++) {
                                var player = payload[i];
                                var pid = player.pid + ''; //Convert to String
                                if(!(pid in this.players)){
                                    this.players[pid] = new HeosPlayer(this, player);
                                }
                                connectedPlayers.push(pid);
                            }
                            //Remove disconnected players
                            for(var pid in this.players) {
                                if(!connectedPlayers.includes(pid)){
                                    this.stopPlayer(pid);
                                }
                            }
                        } catch (err) { this.logError('startPlayers: ' + err.message); }
                    }
                
                    //Alle Player stoppen
                    stopPlayers() {
                        this.logDebug("Try to stop players:" + JSON.stringify(Object.keys(this.players)));
                        for (var pid in this.players) {
                            this.stopPlayer(pid);
                        }
                    }
                
                    // setzen der Werte einer Group
                    setGroup(group) {
                        if (group.hasOwnProperty('pid')) {
                            // in den Playern den Groupstatus setzen
                            var pids = group.pid.split(',');
                
                            for (var i = 0; i < pids.length; i++) {
                                this.setState(pids[i] + '.group_name', (group.hasOwnProperty('name') ? group.name : ''));
                                this.setState(pids[i] + '.group_pid', group.pid);
                                this.setState(pids[i] + '.group_leader', (i == 0) && (pids.length > 1));
                                this.setState(pids[i] + '.group_member', (pids.length > 1));
                            }
                
                            if (group.hasOwnProperty('gid')) {
                                // volume und mute dazu holen
                                this.executeCommand("group/get_volume?gid=" + group.gid);
                                this.executeCommand("group/get_mute?gid=" + group.gid);
                            }
                        }
                
                    }
                
                    getPlayers() {
                        if (this.state == stateCONNECTED) {
                            this.msgs.push('heos://player/get_players\n');
                            this.sendNextMsg();
                        }
                    }
                
                    registerChangeEvents(b) {
                        if (this.state == stateCONNECTED) {
                            if (b) this.msgs.push('heos://system/register_for_change_events?enable=on');
                            else this.msgs.push('heos://system/register_for_change_events?enable=off');
                            this.sendNextMsg();
                        }
                    }
                
                    signIn() {
                        if (this.state == stateCONNECTED) {
                            // heos://system/sign_in?un=heos_username&pw=heos_password
                            this.msgs.push('heos://system/sign_in?un=' + HEOS_USERNAME + '&pw=' + HEOS_PASSWORD);
                            this.sendNextMsg();
                        }
                    }
                
                    getMusicSources() {
                        if (this.state == stateCONNECTED) {
                            // heos://browse/get_music_sources
                            this.msgs.push('heos://browse/get_music_sources');
                            this.sendNextMsg();
                        }
                
                    }
                
                    getGroups() {
                        if (this.state == stateCONNECTED) {
                            // heos://group/get_groups
                            this.msgs.push('heos://group/get_groups');
                            this.sendNextMsg();
                        }
                
                    }
                
                    startHeartbeat() {
                        if (this.state == stateCONNECTED) {
                            this.logDebug("start heartbeat interval");
                            this.heartbeatInterval = setInterval(() => {
                                this.logDebug("heartbeat")
                                this.msgs.push('heos://system/heart_beat');
                                this.sendNextMsg();
                                if (typeof this.heartbeatTimeout == undefined) {
                                    this.heartbeatTimeout = setTimeout(() => {
                                        this.log("heartbeat timeout");
                                        this.reboot();
                                        setTimeout(() => {
                                            this.reconnect();
                                        }, 1000)
                                    }, HEARTBEAT_TIMEOUT);
                                }
                            }, HEARTBEAT_INTERVAL);
                        }
                    }
                
                    resetHeartbeatTimeout() {
                        this.logDebug("reset heartbeat timeout");
                        if (this.heartbeatTimeout) {
                            clearTimeout(this.heartbeatTimeout);
                            this.heartbeatTimeout = undefined;
                        }
                    }
                
                    stopHeartbeat() {
                        this.logDebug("stop heartbeat interval");
                        if (this.heartbeatInterval) {
                            clearInterval(this.heartbeatInterval);
                            this.heartbeatInterval = undefined;
                        }
                        this.resetHeartbeatTimeout();
                    }
                
                    reboot() {
                        if (this.state == stateCONNECTED) {
                            this.logDebug("reboot device");
                            // heos://system/reboot
                            this.msgs.push('heos://system/reboot');
                            this.sendNextMsg();
                        }
                    }
                
                    browse(sid) {
                        if (this.state == stateCONNECTED) {
                            // heos://browse/browse?sid=source_id
                            this.msgs.push('heos://browse/browse?sid=' + sid);
                            this.sendNextMsg();
                        }
                    }
                
                
                    sendNextMsg() {
                        if (this.msgs.length > 0) {
                            var msg = this.msgs.shift();
                            this.sendMsg(msg);
                        }
                    }
                
                    // Nachricht an player senden
                    sendMsg(msg) {
                        this.net_client.write(msg + "\n");
                        this.logDebug("data sent: " + msg);
                    }
                
                
                } // end of class Heos
                
                /********************
                 * class HeosPlayer
                 ********************/
                
                class HeosPlayer {
                
                    logDebug(msg) { console.debug('[HeosPlayer ' + this.pid + '] ' + msg); }
                    log(msg) { console.log('[HeosPlayer ' + this.pid + '] ' + msg); }
                    logWarn(msg) { console.warn('[HeosPlayer ' + this.pid + '] ' + msg); }
                    logError(msg) { console.error('[HeosPlayer ' + this.pid + '] ' + msg); }
                
                    constructor(heos, player) {
                        this.heos = heos;
                        this.ip = player.ip;
                        this.name = player.name;
                        this.pid = player.pid;
                        this.model = player.model;
                        this.serial = player.serial;
                        this.onHandler = [];
                
                        //    this.statePath = 'javascript.'+instance+'.heos.'+this.ip.replace(/\./g,'_')+".";
                        this.statePath = '0_userdata.0.heos.' + this.pid + ".";
                
                        this.log('creating HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
                
                        this.states = [
                            { id: "connected", common: { name: "Verbunden?" } },
                            { id: "command", common: { name: "Befehl an Heos Player senden" } },
                            { id: "ip", common: { name: "IP-Adresse", write: false } },
                            { id: "pid", common: { name: "Player-ID", write: false } },
                            { id: "name", common: { name: "Name des Players", write: false } },
                            { id: "model", common: { name: "Modell des Players", write: false } },
                            { id: "serial", common: { name: "Seriennummer des Players", write: false } },
                            { id: "last_error", common: { name: "Letzte Fehler", write: false } },
                            { id: "volume", common: { name: "Aktuelle Lautstärke" } },
                            { id: "mute", common: { name: "Mute aktiviert?" } },
                            { id: "play_state", common: { name: "Aktueller Wiedergabezustand" } },
                            { id: "play_mode_repeat", common: { name: "Wiedergabewiederholung" } },
                            { id: "play_mode_shuffle", common: { name: "Zufällige Wiedergabe" } },
                            { id: "now_playing_media_type", common: { name: "Aktuelle Wiedergabemedium", write: false } },
                            { id: "now_playing_media_song", common: { name: "Aktuelles Lied", write: false } },
                            { id: "now_playing_media_station", common: { name: "Aktuelle Station", write: false } },
                            { id: "now_playing_media_album", common: { name: "Aktuelle Wiedergabemedium", write: false } },
                            { id: "now_playing_media_artist", common: { name: "Aktueller Artist", write: false } },
                            { id: "now_playing_media_image_url", common: { name: "Aktuelles Coverbild", write: false } },
                            { id: "now_playing_media_album_id", common: { name: "Aktuelle Album-ID", write: false } },
                            { id: "now_playing_media_mid", common: { name: "Aktuelle mid", write: false } },
                            { id: "now_playing_media_qid", common: { name: "Aktuelle qid", write: false } },
                            { id: "cur_pos", common: { name: "lfd. Position" } },
                            { id: "duration", common: { name: "Dauer", write: false } },
                            { id: "cur_pos_MMSS", common: { name: "lfd. Position MM:SS" } },
                            { id: "duration_MMSS", common: { name: "Dauer MM:SS", write: false } },
                            { id: "group_leader", common: { name: "Ist Gruppenleiter", write: false } },
                            { id: "group_member", common: { name: "Ist Gruppenmitglied", write: false } },
                            { id: "group_pid", common: { name: "PlayerIDs in der Gruppe", write: false } },
                            { id: "group_volume", common: { name: "Lautstärke wenn Gruppen-Leiter" } },
                            { id: "group_name", common: { name: "Name der Gruppe", write: false } },
                            { id: "group_mute", common: { name: "Gruppe gemutet?" } },
                            { id: "script_version", common: { name: "Installierte Script-Version", write: false } }
                        ];
                        // beim 1.Start die states erzeugen
                        if (!this.existState("script_version") || this.getState('script_version').val != SCRIPTVERSION) {
                            this.installed = false;
                            this.logWarn('creating HEOS player states for version ' + SCRIPTVERSION + ', please start script again');
                            // states erzeugen
                            for (var s = 0; s < this.states.length; s++) {
                                this.setState(this.states[s].id, "");
                            }
                            this.setState('script_version', SCRIPTVERSION);
                        }
                        else {
                            // Initialisierung der States nach 5 Sek
                            setTimeout(() => {
                                this.setState('ip', this.ip);
                                this.setState('name', this.name);
                                this.setState('pid', this.pid);
                                this.setState('model', this.model);
                                this.setState('serial', this.serial);
                                this.sendCommand('get_play_state|get_play_mode|get_now_playing_media|get_volume');
                            }, 5000);
                            setTimeout(() => {
                                this.startPlayer();
                            }, 10000);
                            this.installed = true;
                        }
                    }
                
                    // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                    // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                    existState(id) {
                        return ($(this.statePath + id).length == 0 ? false : true);
                    }
                
                    // wrapper
                    getState(id) {
                        return getState(this.statePath + id);
                    }
                
                    // wie setState(), setzt aber den statePath davor und überpüft aber ob der state vorhanden ist und erzeugt ihn,
                    // wenn er noch nicht da ist
                    setState(id, value) {
                        if (!this.existState(id)) this.createState(id, value, undefined);
                        else setState(this.statePath + id, value, true);
                    }
                
                    // wie createState, setzt aber noch den statePath davor und schaut im states-Array nach, ob dort common-Angaben
                    // vorhanden sind (wenn der common-Parameter leer ist)
                    createState(id, value, common) {
                        if (!this.existState(id)) {
                            if (common === undefined) {
                                // id im states-Array suchen
                                for (var i = 0; i < this.states.length; i++) {
                                    if (this.states[i].id == id) {
                                        if (this.states[i].hasOwnProperty('common'))
                                            common = this.states[i].common;
                                        break;
                                    }
                                }
                            }
                            if ((typeof value === 'undefined') && (common.hasOwnProperty('def'))) value = common.def;
                            // unter "0_userdata.0"
                            let obj = {};
                            obj.type = 'state';
                            obj.native = {};
                            obj.common = common;
                            setObject(this.statePath + id, obj, (err) => {
                                if (err) {
                                    this.log('cant write object for state "' + this.statePath + id + '": ' + err);
                                } else {
                                    this.log('state "' + this.statePath + id + '" created');
                                }
                            });
                
                            // value zeitversetzt setzen        
                            setTimeout(setState, 3000, this.statePath + id, value);
                        }
                    }
                
                
                    startPlayer() {
                        try {
                            this.log('starting HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
                            this.onHandler = [];
                            // on-Event für command
                            this.onHandler.push(on({ id: this.statePath + 'command', change: "any" }, (obj) => {
                                this.executeCommand(obj.id, obj.state.val)
                            }));
                
                            // on-Event für volume (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'volume', change: 'ne', ack: false }, (obj) => {
                                this.executeCommand(obj.id, 'set_volume&level=' + obj.state.val);
                            }));
                            // on-Event für mute (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'mute', change: 'ne', ack: false }, (obj) => {
                                this.executeCommand(obj.id, 'set_mute&state=' + (obj.state.val === true ? 'on' : 'off'));
                            }));
                            // on-Event für play_mode_shuffle (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'play_mode_shuffle', change: 'ne', ack: false }, (obj) => {
                                this.executeCommand(obj.id, 'set_play_mode&shuffle=' + (obj.state.val === true ? 'on' : 'off'));
                            }));
                            // on-Event für play_state (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'play_state', change: 'ne', ack: false }, (obj) => {
                                this.executeCommand(obj.id, 'set_play_state&state=' + obj.state.val);
                            }));
                
                            // on-Event für group-volume (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'group_volume', change: 'ne', ack: false }, (obj) => {
                                // "id":"javascript.1.heos.-1746612370.group_volume"
                                var id = obj.id.split('.');
                                this.executeCommand('group/set_volume?gid=' + id[3] + '&level=' + obj.state.val);
                            }));
                
                            // on-Event für group-mute (nur wenn ack=false, also über vis)
                            this.onHandler.push(on({ id: this.statePath + 'group_mute', change: 'ne', ack: false }, (obj) => {
                                // "id":"javascript.1.heos.-1746612370.group_volume"
                                var id = obj.id.split('.');
                                this.heos.executeCommand('group/set_mute?gid=' + id[3] + '&state=' + (obj.state.val === true ? 'on' : 'off'));
                            }));
                
                            this.setState('connected', true);
                        } catch (err) { this.logError('startPlayer: ' + err.message); }
                    }
                
                    // sucht die zur pid passenden player-Insanz
                    executeCommand(objID, cmd) {
                        // aus der objID die pid holen
                        // objID = javascript.1.heos.394645376.command
                        objID = objID.split('.');
                        var pid = objID[3];
                        if (this.pid == pid) {
                            this.sendCommand(cmd);
                        }
                    }
                
                    cleanupNowPlaying(){
                        for (var s = 0; s < this.states.length; s++) {
                            if(this.states[s].id.startsWith("now_playing")){
                                this.setState(this.states[s].id, "");
                            }
                        }
                    }
                
                
                    stopPlayer() {
                        try {
                            this.log('stopping HEOS player with pid ' + this.pid + ' (' + this.ip + ')');
                
                            // events unsubcribe
                            for (let i = 0; i < this.onHandler.length; i++) {
                                if (this.onHandler[i] !== undefined) unsubscribe(this.onHandler[i]);
                            }
                            this.onHandler = [];
                            //cleanup now playing
                            this.cleanupNowPlaying();
                            // reset last error
                            this.setState("last_error", "");
                            // connected zurücksetzen
                            this.setState("connected", false);
                        } catch (err) { this.logError('stopPlayer: ' + err.message); }
                    }
                
                    /** wandelt einen sek Wert in MM:SS Darstellung um
                     **/
                    toMMSS(s) {
                        var sec_num = parseInt(s, 10);
                        var minutes = Math.floor(sec_num / 60);
                        var seconds = sec_num - (minutes * 60);
                        if (seconds < 10) { seconds = "0" + seconds; }
                        return minutes + ':' + seconds;
                    }
                
                    setLastError(err) {
                        try {
                            this.logWarn(err);
                            let val = this.getState('last_error').val + '';
                            let lines = val.split('\n');
                            if (lines.length > 4)
                                lines.pop();
                            lines.unshift(err + '\n');
                            this.setState('last_error', lines.toString());
                        } catch (e) { this.logError('setLastError: ' + e.message); }
                    }
                
                
                    /** Auswertung der empfangenen Daten
                     **/
                    parseResponse(jdata, jmsg, cmd_group, cmd) {
                        try {
                            switch (cmd_group) {
                                case 'event':
                                    switch (cmd) {
                                        case 'player_playback_error':
                                            this.setLastError(jmsg.error.replace(/_/g, ' '));
                                            break;
                                        case 'player_state_changed':
                                            this.setState("play_state", jmsg.state);
                                            this.sendCommand('get_now_playing_media');
                                            break;
                                        case 'player_volume_changed':
                                            this.setState("volume", jmsg.level);
                                            this.setState("mute", (jmsg.mute == 'on' ? true : false));
                                            break;
                                        case 'player_repeat_mode_changed':
                                            this.setState("play_mode_shuffle", jmsg.shuffle);
                                            break;
                                        case 'player_shuffle_mode_changed':
                                            this.setState("play_mode_repeat", jmsg.repeat);
                                            break;
                                        case 'player_now_playing_changed':
                                            this.sendCommand('get_now_playing_media');
                                            break;
                                        case 'player_now_playing_progress':
                                            this.setState("cur_pos", jmsg.cur_pos / 1000);
                                            this.setState("cur_pos_MMSS", this.toMMSS(jmsg.cur_pos / 1000));
                                            this.setState("duration", jmsg.duration / 1000);
                                            this.setState("duration_MMSS", this.toMMSS(jmsg.duration / 1000));
                                            break;
                                    }
                                    break;
                
                
                                case 'player':
                                    switch (cmd) {
                                        case 'set_volume':
                                        case 'get_volume':
                                            if (getState(this.statePath + "volume").val != jmsg.level)
                                                this.setState("volume", jmsg.level);
                                            break;
                                        case 'set_mute':
                                        case 'get_mute':
                                            this.setState("mute", (jmsg.state == 'on' ? true : false));
                                            break;
                                        case 'set_play_state':
                                        case 'get_play_state':
                                            this.setState("play_state", jmsg.state);
                                            break;
                                        case 'set_play_mode':
                                        case 'get_play_mode':
                                            this.setState("play_mode_repeat", jmsg.repeat);
                                            this.setState("play_mode_shuffle", (jmsg.shuffle == 'on' ? true : false));
                                            break;
                                        case 'get_now_playing_media':
                                            this.setState("now_playing_media_type", jdata.payload.type);
                                            if (jdata.payload.hasOwnProperty('song'))
                                                this.setState("now_playing_media_song", jdata.payload.song);
                                            if (jdata.payload.hasOwnProperty('album'))
                                                this.setState("now_playing_media_album", jdata.payload.album);
                                            if (jdata.payload.hasOwnProperty('album_id'))
                                                this.setState("now_playing_media_album_id", jdata.payload.album_id);
                                            if (jdata.payload.hasOwnProperty('artist'))
                                                this.setState("now_playing_media_artist", jdata.payload.artist);
                                            if (jdata.payload.hasOwnProperty('image_url'))
                                                this.setState("now_playing_media_image_url", jdata.payload.image_url);
                                            if (jdata.payload.hasOwnProperty('mid'))
                                                this.setState("now_playing_media_mid", jdata.payload.mid);
                                            if (jdata.payload.hasOwnProperty('qid'))
                                                this.setState("now_playing_media_qid", jdata.payload.qid);
                                            if (jdata.payload.hasOwnProperty('type')) {
                                                if (jdata.payload.type == 'station') {
                                                    this.setState("now_playing_media_station", jdata.payload.station);
                                                } else {
                                                    this.setState("now_playing_media_station", "");
                                                }
                                            }
                                            break;
                                    }
                                    break;
                            } // switch
                
                
                        } catch (err) { this.logError('parseResponse: ' + err.message); }
                    }
                
                    /** cmd der Form "cmd&param"  werden zur msg heos+cmd+pid+&param aufbereitet
                        cmd der Form "cmd?param"  werden zur msg heos+cmd+?param aufbereitet
                     **/
                    commandToMsg(cmd) {
                        var param = cmd.split('&');
                        cmd = param[0];
                        if (param.length > 1) param = '&' + param[1]; else param = '';
                        var cmd_group = 'player';
                
                        switch (cmd) {
                            case 'get_play_state':
                            case 'get_play_mode':
                            case 'get_now_playing_media':
                            case 'get_volume':
                            case 'play_next':
                            case 'play_previous':
                            case 'set_mute':       // &state=on|off        
                            case 'set_volume':     // &level=1..100   
                            case 'volume_down':    // &step=1..10   
                            case 'volume_up':      // &step=1..10
                            case 'set_play_state': // &state=play|pause|stop
                            case 'set_play_mode':  // &repeat=on_all|on_one|off  shuffle=on|off
                                break;
                
                            // browse            
                            case 'play_preset':    // heos://browse/play_preset?pid=player_id&preset=preset_position
                                cmd_group = 'browse';
                                break;
                            case 'play_stream':    // heos://browse/play_stream?pid=player_id&url=url_path
                                cmd_group = 'browse';
                                break;
                
                        }
                        return 'heos://' + cmd_group + '/' + cmd + '?pid=' + this.pid + param;
                    }
                
                    /** Nachricht (command) an player senden
                        es sind auch mehrere commands, getrennt mit | erlaubt
                        bsp: set_volume&level=20|play_preset&preset=1
                     **/
                    sendCommand(command) {
                        if (!this.installed) return;
                
                        var cmds = command.split('|');
                        for (var c = 0; c < cmds.length; c++) {
                            this.heos.msgs.push(this.commandToMsg(cmds[c]));
                        }
                        this.heos.sendNextMsg();
                    }
                
                
                } // end of HeosPlayer
                
                
                /* -----
                   Heos
                   ----- */
                // Heos Instanz erzeugen und verbinden   
                var heos = new Heos();
                heos.connect();
                
                // wenn das Script beendet wird, dann auch die Heos Instanz beenden
                onStop(function () {
                    heos.disconnect();
                }, 0);
                
                UhulaU Offline
                UhulaU Offline
                Uhula
                schrieb am zuletzt editiert von
                #105

                @withstu sagte in [Vorlage] Denon HEOS Script:

                Ich habe in den letzten Tagen noch ein paar Bugs gefixt

                Super, wenn ich Zeit finde (ist ja bald Ostern), schau ich rein und übernehme es. Hinweis: Wenn du das Script hier als code postest, versieht es das Forum mit zufällligen {1} Einträgen; besser ist es das Script als Datei (z.B.: heos.js) hochzuladen.

                Uhula - Leise und Weise
                Ex: ioBroker on Gigabyte NUC Proxmox

                1 Antwort Letzte Antwort
                0
                • W withstu

                  @chrisblu Ich habe für jeden Lautsprecher einen Ping Adapter angelegt. Sobald sich da was ändert und in den HEOS Objekten der Player noch nicht verbunden ist, starte ich das Script neu (bei mir sind die Player nicht dauerhaft verbunden). Übrigens ich hatte total vergessen, dass das connected Flag der Player im disconnect wieder auf false gesetzt wird.
                  Mein Blockly Heos Script Starter sieht so aus (kann bestimmt auch eleganter gelöst werden, ich nutze jedoch iobroker erst seit kurzem):

                  var DelayedUnlock;
                  
                  
                  schedule("*/15 * * * * *", function () {
                    if (getState("0_userdata.0.scriptData.HEOSScriptStarterRunning").val == true && ((new Date().getTime()) - getState("0_userdata.0.scriptData.HEOSScriptStarterRunning").lc) / 1000 > 300) {
                      setState("0_userdata.0.scriptData.HEOSScriptStarterRunning"/*HEOSScriptStarterRunning*/, false);
                    }
                    if (getState("0_userdata.0.scriptData.HEOSScriptStarterRunning").val == false) {
                      setState("0_userdata.0.scriptData.HEOSScriptStarterRunning"/*HEOSScriptStarterRunning*/, true);
                      DelayedUnlock = false;
                      if (getState("javascript.0.scriptEnabled.common.HEOS").val == true && getState("javascript.0.heos.connected").val == false) {
                        console.log('HEOS not connected. Shutdown.');
                        setState("javascript.0.scriptEnabled.common.HEOS"/*scriptEnabled.common.HEOS*/, false);
                      } else if (getState("javascript.0.scriptEnabled.common.HEOS").val == true && (getState("javascript.0.heos.192_168_178_43.connected").val != getState("ping.0.server.192_168_178_43").val || getState("javascript.0.heos.192_168_178_44.connected").val != getState("ping.0.server.192_168_178_44").val || getState("javascript.0.heos.192_168_178_45.connected").val != getState("ping.0.server.192_168_178_45").val || getState("javascript.0.heos.192_168_178_46.connected").val != getState("ping.0.server.192_168_178_46").val)) {
                        console.log('HEOS Player updated. Shutdown.');
                        setState("javascript.0.scriptEnabled.common.HEOS"/*scriptEnabled.common.HEOS*/, false);
                      } else {
                        if (getState("ping.0.server.192_168_178_45").val == false && getState("ping.0.server.192_168_178_44").val == false && getState("ping.0.server.192_168_178_43").val == false && getState("ping.0.server.192_168_178_46").val == false) {
                          if (getState("javascript.0.scriptEnabled.common.HEOS").val == true) {
                            console.log('No Players. Shutdown.');
                            setState("javascript.0.scriptEnabled.common.HEOS"/*scriptEnabled.common.HEOS*/, false);
                            DelayedUnlock = true;
                          }
                        } else {
                          if (getState("javascript.0.scriptEnabled.common.HEOS").val == false) {
                            console.log('Players available. Startup.');
                            setState("javascript.0.scriptEnabled.common.HEOS"/*scriptEnabled.common.HEOS*/, true);
                            DelayedUnlock = true;
                          }
                        }
                      }
                      if (DelayedUnlock == true) {
                        setStateDelayed("0_userdata.0.scriptData.HEOSScriptStarterRunning"/*HEOSScriptStarterRunning*/, false, 60000, false);
                      } else {
                        setState("0_userdata.0.scriptData.HEOSScriptStarterRunning"/*HEOSScriptStarterRunning*/, false);
                      }
                    }
                  });
                  

                  Zu jedem Player gibt es dann noch ein Script, welches im Notfall das connected Flag wieder auf false setzt (und automatisch die Musik und Lautstärker steuert :-) ) :

                  var DelayedUnlock, Volume, Preset;
                  
                  
                  on({id: new RegExp('javascript\\.0\\.heos\\.192_168_178_45\\.mute' + "|" + 'javascript\\.0\\.heos\\.192_168_178_45\\.connected' + "|" + 'ping\\.0\\.server\\.192_168_178_45' + "|" + 'javascript\\.0\\.heos\\.connected'), change: "ne"}, function (obj) {
                      if (getState("0_userdata.0.scriptData.BadezimmerAutoPlayRunning").val == false) {
                      setState("0_userdata.0.scriptData.BadezimmerAutoPlayRunning"/*scriptData.BadezimmerAutoPlayRunning*/, true);
                      DelayedUnlock = false;
                      if (getState("javascript.0.heos.connected").val == false && getState("javascript.0.heos.192_168_178_45.connected").val == true && getState("ping.0.server.192_168_178_45").val == false) {
                        setState("javascript.0.heos.192_168_178_45.connected"/*Verbunden?*/, false);
                      }
                      if (getState("javascript.0.heos.192_168_178_45.connected").val == true && getState("javascript.0.heos.192_168_178_45.mute").val == false && (getState("javascript.0.heos.192_168_178_45.play_state").val == 'stop' || getState("javascript.0.heos.192_168_178_45.play_state").val == 'pause')) {
                        console.log('Starte Musik im Badezimmer.');
                        if ((new Date().getHours()) >= 22 || (new Date().getHours()) <= 7) {
                          Volume = getState("0_userdata.0.scriptData.NachtVolume").val;
                        } else {
                          Volume = getState("0_userdata.0.scriptData.TagVolume").val;
                        }
                        setState("javascript.0.heos.192_168_178_45.volume"/*Aktuelle Lautstärke*/, Volume);
                        if (getState("javascript.0.heos.192_168_178_45.now_playing_media_album_id").val.indexOf('ios-ipod-library') + 1 > 0 || getState("javascript.0.heos.192_168_178_45.last_error").val.length > 0) {
                          if ((new Date().getDay() === 0 ? 7 : new Date().getDay()) == 0) {
                            Preset = getState("0_userdata.0.scriptData.SonntagPreset").val;
                          } else {
                            Preset = getState("0_userdata.0.scriptData.DefaultPreset").val;
                          }
                          setState("javascript.0.heos.192_168_178_45.command"/*Kommando für HEOS Aufrufe*/, ('play_preset&preset=' + String(Preset)));
                        } else {
                          setState("javascript.0.heos.192_168_178_45.play_state"/*Aktueller Wiedergabezustand*/, 'play');
                        }
                        DelayedUnlock = true;
                      }
                      if (DelayedUnlock == true) {
                        setStateDelayed("0_userdata.0.scriptData.BadezimmerAutoPlayRunning"/*scriptData.BadezimmerAutoPlayRunning*/, false, 60000, false);
                      } else {
                        setState("0_userdata.0.scriptData.BadezimmerAutoPlayRunning"/*scriptData.BadezimmerAutoPlayRunning*/, false);
                      }
                    }
                  });
                  
                  schedule("* * * * *", function () {
                    if (getState("javascript.0.heos.192_168_178_45.connected").val == true) {
                      if ((new Date().getHours()) >= 22 || (new Date().getHours()) <= 7) {
                        if (getState("0_userdata.0.scriptData.BadezimmerAutoVolume").val != 'Nacht') {
                          Volume = getState("0_userdata.0.scriptData.NachtVolume").val;
                          if (getState("javascript.0.heos.192_168_178_45.volume").val != Volume) {
                            setState("javascript.0.heos.192_168_178_45.volume"/*Aktuelle Lautstärke*/, Volume);
                          }
                          setState("0_userdata.0.scriptData.BadezimmerAutoVolume"/*BadezimmerAutoVolume*/, 'Nacht');
                        }
                      } else {
                        if (getState("0_userdata.0.scriptData.BadezimmerAutoVolume").val != 'Tag') {
                          Volume = getState("0_userdata.0.scriptData.TagVolume").val;
                          if (getState("javascript.0.heos.192_168_178_45.volume").val != Volume) {
                            setState("javascript.0.heos.192_168_178_45.volume"/*Aktuelle Lautstärke*/, Volume);
                          }
                          setState("0_userdata.0.scriptData.BadezimmerAutoVolume"/*BadezimmerAutoVolume*/, 'Tag');
                        }
                      }
                    }
                  });
                  
                  C Offline
                  C Offline
                  chrisblu
                  schrieb am zuletzt editiert von chrisblu
                  #106

                  @withstu

                  Ich habe für jeden Lautsprecher einen Ping Adapter angelegt. Sobald sich da was ändert und in den HEOS Objekten der Player noch nicht verbunden ist, starte ich das Script neu (bei mir sind die Player nicht dauerhaft verbunden).

                  Ich komme gerade erst dazu mir das mit der Ping-Überprüfung anzuschauen. Ist das mit dem neuen Skript überhaupt noch erforderlich? Wahrscheinlich ja, weil bei mir sind immer wieder Boxen nicht erreichbar.
                  Du schreibst, das ist ein Blockly-Skript, aber die Definition sieht eher aus wie ein Java-Script. Könntest Du mir das als Blockly exportieren, oder hast du das in Java umgewandelt.

                  Vielen Dank auf jeden Fall für Eure Mühen, das Heos Skript läuft sonst sehr gut bei mir.

                  Danke,
                  Christian

                  W 1 Antwort Letzte Antwort
                  0
                  • C chrisblu

                    @withstu

                    Ich habe für jeden Lautsprecher einen Ping Adapter angelegt. Sobald sich da was ändert und in den HEOS Objekten der Player noch nicht verbunden ist, starte ich das Script neu (bei mir sind die Player nicht dauerhaft verbunden).

                    Ich komme gerade erst dazu mir das mit der Ping-Überprüfung anzuschauen. Ist das mit dem neuen Skript überhaupt noch erforderlich? Wahrscheinlich ja, weil bei mir sind immer wieder Boxen nicht erreichbar.
                    Du schreibst, das ist ein Blockly-Skript, aber die Definition sieht eher aus wie ein Java-Script. Könntest Du mir das als Blockly exportieren, oder hast du das in Java umgewandelt.

                    Vielen Dank auf jeden Fall für Eure Mühen, das Heos Skript läuft sonst sehr gut bei mir.

                    Danke,
                    Christian

                    W Offline
                    W Offline
                    withstu
                    schrieb am zuletzt editiert von
                    #107

                    @chrisblu Mit der zweiten Version ist der Ping Adapter nicht mehr notwendig und auch ein Neustart des Scripts ist nicht mehr erforderlich. Mein Script läuft mittlerweile seit über einer Woche stabil und erkennt automatisch Player die neu hinzukommen oder ausgeschaltet werden. In der nachfolgenden Version habe ich noch Fehler in dem Heartbeat Mechanismus gelöst. Das einzige was mich noch stört ist das Feld "last error", welches nach der Lösung des Fehlers nicht geleert wird. So wird der Fehler bei mir im vis noch angezeigt, obwohl er nicht mehr besteht. Mal schauen, ob mir in den nächsten Tagen noch was dazu einfällt: HEOS.json

                    1 Antwort Letzte Antwort
                    0
                    • C Offline
                      C Offline
                      chrisblu
                      schrieb am zuletzt editiert von
                      #108

                      @withstu Vielen Dank für die aktuelle Version des Skripts. Während die letzte Fassung bei mir regelmäßig abgestürzt ist (das Pausezeichen in den Skripts war gelb und nichts ging mehr bis ich den Javascript-Adapter wieder gestartet hab), läuft dieses jetzt scheinbar stabil.

                      Das mit dem last error finde ich nicht ganz so schlimm, da man ja am TimeStamp erkennt, wann der aufgetreten ist. Könnte man vielleicht zum last error einen Flag einführen, ob der Fehler noch anhält oder nicht?

                      Aber super Skript...
                      vielen Dank
                      Christian

                      W 1 Antwort Letzte Antwort
                      0
                      • C chrisblu

                        @withstu Vielen Dank für die aktuelle Version des Skripts. Während die letzte Fassung bei mir regelmäßig abgestürzt ist (das Pausezeichen in den Skripts war gelb und nichts ging mehr bis ich den Javascript-Adapter wieder gestartet hab), läuft dieses jetzt scheinbar stabil.

                        Das mit dem last error finde ich nicht ganz so schlimm, da man ja am TimeStamp erkennt, wann der aufgetreten ist. Könnte man vielleicht zum last error einen Flag einführen, ob der Fehler noch anhält oder nicht?

                        Aber super Skript...
                        vielen Dank
                        Christian

                        W Offline
                        W Offline
                        withstu
                        schrieb am zuletzt editiert von
                        #109

                        @chrisblu Gute Idee. Habe ich hinzugefügt: HEOS.js

                        Meister MopperM 1 Antwort Letzte Antwort
                        0
                        • W withstu

                          @chrisblu Gute Idee. Habe ich hinzugefügt: HEOS.js

                          Meister MopperM Abwesend
                          Meister MopperM Abwesend
                          Meister Mopper
                          schrieb am zuletzt editiert von
                          #110

                          Komisch, irgendwas läuft da falsch. Bem Erststart nach ioBroker-Neustart möchte sich das Script mit meiner Hue-Bridge (...72:1255) verbinden. Wie ist das zu erklären, jemand eine Idee?

                          Beim Neustart des Scripts wird keine Verbindung mehr zur Hue-Bridge gesucht und das Script läuft fehlerfrei.

                          javascript.1	2020-04-14 18:47:06.030	info	(18421) Stop script script.js.java.sonstige.heos
                          javascript.1	2020-04-14 18:46:25.905	error	(18421) at process._tickCallback (internal/process/next_tick.js:63:19)
                          javascript.1	2020-04-14 18:46:25.905	error	(18421) at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
                          javascript.1	2020-04-14 18:46:25.904	error	(18421) at emitErrorNT (internal/streams/destroy.js:91:8)
                          javascript.1	2020-04-14 18:46:25.904	error	(18421) at Socket.emit (events.js:198:13)
                          javascript.1	2020-04-14 18:46:25.904	error	(18421) at Socket.net_client.on (script.js.java.sonstige.heos:384:18)
                          javascript.1	2020-04-14 18:46:25.904	error	(18421) at Heos.disconnect (script.js.java.sonstige.heos:298:30)
                          javascript.1	2020-04-14 18:46:25.903	error	(18421) script.js.java.sonstige.heos: TypeError: this.nodessdp_client.destroy is not a function
                          javascript.1	2020-04-14 18:46:25.902	info	(18421) script.js.java.sonstige.heos: [Heos] disconnecting from HEOS ...
                          javascript.1	2020-04-14 18:46:25.901	error	(18421) script.js.java.sonstige.heos: [Heos] Error: connect ECONNREFUSED 192.168.178.72:1255
                          javascript.1	2020-04-14 18:46:25.891	info	(18421) script.js.java.sonstige.heos: [Heos] connecting to 192.168.178.72 ...
                          javascript.1	2020-04-14 18:46:25.758	info	(18421) script.js.java.sonstige.heos: registered 1 subscription and 0 schedules
                          javascript.1	2020-04-14 18:46:25.754	info	(18421) script.js.java.sonstige.heos: [Heos] connecting to HEOS ...
                          javascript.1	2020-04-14 18:46:25.730	info	(18421) Start javascript script.js.java.sonstige.heos
                          

                          Proxmox und HA

                          W 1 Antwort Letzte Antwort
                          0
                          • Meister MopperM Meister Mopper

                            Komisch, irgendwas läuft da falsch. Bem Erststart nach ioBroker-Neustart möchte sich das Script mit meiner Hue-Bridge (...72:1255) verbinden. Wie ist das zu erklären, jemand eine Idee?

                            Beim Neustart des Scripts wird keine Verbindung mehr zur Hue-Bridge gesucht und das Script läuft fehlerfrei.

                            javascript.1	2020-04-14 18:47:06.030	info	(18421) Stop script script.js.java.sonstige.heos
                            javascript.1	2020-04-14 18:46:25.905	error	(18421) at process._tickCallback (internal/process/next_tick.js:63:19)
                            javascript.1	2020-04-14 18:46:25.905	error	(18421) at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
                            javascript.1	2020-04-14 18:46:25.904	error	(18421) at emitErrorNT (internal/streams/destroy.js:91:8)
                            javascript.1	2020-04-14 18:46:25.904	error	(18421) at Socket.emit (events.js:198:13)
                            javascript.1	2020-04-14 18:46:25.904	error	(18421) at Socket.net_client.on (script.js.java.sonstige.heos:384:18)
                            javascript.1	2020-04-14 18:46:25.904	error	(18421) at Heos.disconnect (script.js.java.sonstige.heos:298:30)
                            javascript.1	2020-04-14 18:46:25.903	error	(18421) script.js.java.sonstige.heos: TypeError: this.nodessdp_client.destroy is not a function
                            javascript.1	2020-04-14 18:46:25.902	info	(18421) script.js.java.sonstige.heos: [Heos] disconnecting from HEOS ...
                            javascript.1	2020-04-14 18:46:25.901	error	(18421) script.js.java.sonstige.heos: [Heos] Error: connect ECONNREFUSED 192.168.178.72:1255
                            javascript.1	2020-04-14 18:46:25.891	info	(18421) script.js.java.sonstige.heos: [Heos] connecting to 192.168.178.72 ...
                            javascript.1	2020-04-14 18:46:25.758	info	(18421) script.js.java.sonstige.heos: registered 1 subscription and 0 schedules
                            javascript.1	2020-04-14 18:46:25.754	info	(18421) script.js.java.sonstige.heos: [Heos] connecting to HEOS ...
                            javascript.1	2020-04-14 18:46:25.730	info	(18421) Start javascript script.js.java.sonstige.heos
                            
                            W Offline
                            W Offline
                            withstu
                            schrieb am zuletzt editiert von
                            #111

                            @Meister-Mopper Welche Version verwendest du denn? Diesen Fehler hatte ich damals auch und hatte den Fehler bereits in folgendem Beitrag gefixt: https://forum.iobroker.net/topic/10420/vorlage-denon-heos-script/93
                            Das Problem ist, dass das Filtern der Pakete von node-ssdp nicht korrekt durchgeführt wird und versucht wurde sich mit dem ersten Paket was reinkommt zu verbinden. Das kann auch mal ein Hue Paket sein.
                            Ich hatte bei mir die folgende Überprüfung in die onNodeSSDPResponse Funktion eingebaut.

                            if (headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                               this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
                            } else {
                            
                            Meister MopperM 1 Antwort Letzte Antwort
                            0
                            • W withstu

                              @Meister-Mopper Welche Version verwendest du denn? Diesen Fehler hatte ich damals auch und hatte den Fehler bereits in folgendem Beitrag gefixt: https://forum.iobroker.net/topic/10420/vorlage-denon-heos-script/93
                              Das Problem ist, dass das Filtern der Pakete von node-ssdp nicht korrekt durchgeführt wird und versucht wurde sich mit dem ersten Paket was reinkommt zu verbinden. Das kann auch mal ein Hue Paket sein.
                              Ich hatte bei mir die folgende Überprüfung in die onNodeSSDPResponse Funktion eingebaut.

                              if (headers.ST !== this.ssdpSearchTargetName) { // korrektes SSDP
                                 this.logDebug('onNodeSSDPResponse: Getting wrong SSDP entry. Keep trying...');
                              } else {
                              
                              Meister MopperM Abwesend
                              Meister MopperM Abwesend
                              Meister Mopper
                              schrieb am zuletzt editiert von
                              #112

                              @withstu Ich nutze eine alte Version aus dem vorigen Jahr, weil ich die neue (aus dem ersten Beitrag) nicht zum Laufen bekomme (s. log)

                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform._read (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:177:10)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger._transform (/opt/iobroker/node_modules/winston/lib/winston/logger.js:305:12)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:139:32)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Readable.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:241:10)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at readableAddChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:280:11)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at addChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:298:12)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.emit (events.js:203:15)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.ondata (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:681:20)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.Writable.write (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:334:11)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at writeOrBuffer (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:417:5)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at doWrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:428:64)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport._write (/opt/iobroker/node_modules/winston-transport/index.js:81:19)
                              javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.log (/opt/iobroker/node_modules/iobroker.js-controller/lib/logger.js:55:9)
                              javascript.0	2020-04-15 10:08:10.948	error	(834) at WritableState.onwrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:180:5)
                              javascript.0	2020-04-15 10:08:10.948	error	(834) script.js.java.sonstige.Heos_neu: RangeError: Maximum call stack size exceeded
                              javascript.0	2020-04-15 10:08:10.865	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.861	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.861	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.857	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.857	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.854	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.854	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.852	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.852	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.849	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.849	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.841	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.841	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.838	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.838	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.835	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.835	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.830	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.830	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.828	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.828	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.825	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.825	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.822	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.822	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.820	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.819	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.811	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.811	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.809	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.808	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.806	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.806	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.803	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.803	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.801	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.801	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.798	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.798	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.795	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.795	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.790	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.790	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.778	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.778	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.776	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.776	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.773	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.773	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.770	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.770	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.767	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.767	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.765	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.765	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.762	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.762	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.760	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.760	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.752	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.752	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.749	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.749	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.746	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.746	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.744	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.744	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.741	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.741	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.739	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.739	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.736	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.736	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.734	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.734	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.726	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.726	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.723	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.723	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.720	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.720	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.718	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.718	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.715	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.715	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.713	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.713	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.710	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.710	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.708	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.707	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.699	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.699	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.696	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.696	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.694	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.694	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.691	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.691	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.689	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.689	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.686	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.686	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.684	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.684	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.681	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.681	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.673	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.673	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.670	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.670	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.667	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.667	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.665	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.665	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.662	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.662	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.660	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.660	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.657	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.657	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.654	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.654	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.646	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.646	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.644	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.643	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.641	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.641	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.638	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.638	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.635	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.635	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.633	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.633	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.630	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.630	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.628	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.628	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.620	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.620	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.617	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.617	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.615	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.615	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.612	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.612	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.610	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.610	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.607	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.607	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.605	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.605	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.602	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.602	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.595	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.595	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.592	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.592	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.589	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.589	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.587	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.587	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.585	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.584	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.582	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.582	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.580	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.580	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.577	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.577	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.569	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.569	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.567	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.567	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.564	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.564	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.562	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.562	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.560	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.560	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.557	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.557	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.555	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.555	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.552	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.552	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.544	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              javascript.0	2020-04-15 10:08:10.544	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                              javascript.0	2020-04-15 10:08:10.542	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                              

                              Proxmox und HA

                              Meister MopperM 1 Antwort Letzte Antwort
                              0
                              • Meister MopperM Meister Mopper

                                @withstu Ich nutze eine alte Version aus dem vorigen Jahr, weil ich die neue (aus dem ersten Beitrag) nicht zum Laufen bekomme (s. log)

                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform._read (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:177:10)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger._transform (/opt/iobroker/node_modules/winston/lib/winston/logger.js:305:12)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:139:32)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Readable.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:241:10)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at readableAddChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:280:11)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at addChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:298:12)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.emit (events.js:203:15)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.ondata (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:681:20)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.Writable.write (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:334:11)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at writeOrBuffer (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:417:5)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at doWrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:428:64)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport._write (/opt/iobroker/node_modules/winston-transport/index.js:81:19)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.log (/opt/iobroker/node_modules/iobroker.js-controller/lib/logger.js:55:9)
                                javascript.0	2020-04-15 10:08:10.948	error	(834) at WritableState.onwrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:180:5)
                                javascript.0	2020-04-15 10:08:10.948	error	(834) script.js.java.sonstige.Heos_neu: RangeError: Maximum call stack size exceeded
                                javascript.0	2020-04-15 10:08:10.865	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.861	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.861	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.857	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.857	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.854	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.854	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.852	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.852	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.849	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.849	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.841	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.841	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.838	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.838	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.835	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.835	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.830	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.830	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.828	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.828	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.825	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.825	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.822	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.822	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.820	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.819	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.811	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.811	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.809	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.808	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.806	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.806	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.803	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.803	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.801	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.801	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.798	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.798	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.795	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.795	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.790	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.790	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.778	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.778	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.776	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.776	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.773	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.773	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.770	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.770	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.767	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.767	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.765	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.765	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.762	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.762	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.760	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.760	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.752	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.752	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.749	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.749	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.746	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.746	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.744	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.744	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.741	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.741	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.739	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.739	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.736	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.736	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.734	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.734	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.726	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.726	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.723	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.723	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.720	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.720	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.718	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.718	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.715	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.715	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.713	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.713	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.710	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.710	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.708	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.707	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.699	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.699	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.696	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.696	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.694	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.694	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.691	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.691	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.689	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.689	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.686	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.686	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.684	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.684	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.681	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.681	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.673	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.673	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.670	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.670	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.667	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.667	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.665	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.665	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.662	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.662	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.660	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.660	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.657	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.657	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.654	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.654	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.646	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.646	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.644	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.643	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.641	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.641	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.638	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.638	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.635	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.635	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.633	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.633	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.630	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.630	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.628	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.628	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.620	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.620	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.617	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.617	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.615	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.615	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.612	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.612	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.610	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.610	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.607	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.607	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.605	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.605	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.602	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.602	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.595	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.595	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.592	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.592	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.589	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.589	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.587	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.587	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.585	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.584	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.582	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.582	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.580	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.580	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.577	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.577	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.569	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.569	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.567	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.567	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.564	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.564	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.562	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.562	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.560	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.560	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.557	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.557	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.555	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.555	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.552	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.552	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.544	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.544	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.542	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                

                                Meister MopperM Abwesend
                                Meister MopperM Abwesend
                                Meister Mopper
                                schrieb am zuletzt editiert von
                                #113

                                @Meister-Mopper sagte in [Vorlage] Denon HEOS Script:

                                @withstu Ich nutze eine alte Version aus dem vorigen Jahr, weil ich die neue (aus dem ersten Beitrag) nicht zum Laufen bekomme (s. log)

                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform._read (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:177:10)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger._transform (/opt/iobroker/node_modules/winston/lib/winston/logger.js:305:12)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Transform.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_transform.js:139:32)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.Readable.push (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:241:10)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at readableAddChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:280:11)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at addChunk (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:298:12)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.emit (events.js:203:15)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at DerivedLogger.ondata (/opt/iobroker/node_modules/winston/node_modules/readable-stream/lib/_stream_readable.js:681:20)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.Writable.write (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:334:11)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at writeOrBuffer (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:417:5)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at doWrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:428:64)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport._write (/opt/iobroker/node_modules/winston-transport/index.js:81:19)
                                javascript.0	2020-04-15 10:08:10.949	error	(834) at NotifierTransport.log (/opt/iobroker/node_modules/iobroker.js-controller/lib/logger.js:55:9)
                                javascript.0	2020-04-15 10:08:10.948	error	(834) at WritableState.onwrite (/opt/iobroker/node_modules/readable-stream/lib/_stream_writable.js:180:5)
                                javascript.0	2020-04-15 10:08:10.948	error	(834) script.js.java.sonstige.Heos_neu: RangeError: Maximum call stack size exceeded
                                javascript.0	2020-04-15 10:08:10.865	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.861	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.861	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.857	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.857	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.854	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.854	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.852	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.852	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.849	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.849	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.841	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.841	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.838	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.838	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.835	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.835	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.830	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.830	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.828	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.828	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.825	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.825	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.822	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.822	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.820	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.819	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.811	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.811	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.809	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.808	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.806	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.806	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.803	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.803	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.801	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.801	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.798	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.798	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.795	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.795	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.790	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.790	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.778	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.778	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.776	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.776	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.773	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.773	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.770	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.770	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.767	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.767	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.765	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.765	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.762	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.762	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.760	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.760	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.752	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.752	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.749	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.749	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.746	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.746	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.744	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.744	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.741	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.741	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.739	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.739	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.736	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.736	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.734	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.734	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.726	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.726	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.723	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.723	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.720	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.720	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.718	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.718	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.715	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.715	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.713	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.713	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.710	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.710	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.708	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.707	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.699	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.699	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.696	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.696	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.694	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.694	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.691	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.691	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.689	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.689	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.686	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.686	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.684	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.684	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.681	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.681	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.673	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.673	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.670	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.670	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.667	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.667	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.665	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.665	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.662	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.662	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.660	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.660	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.657	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.657	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.654	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.654	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.646	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.646	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.644	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.643	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.641	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.641	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.638	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.638	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.635	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.635	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.633	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.633	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.630	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.630	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.628	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.628	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.620	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.620	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.617	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.617	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.615	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.615	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.612	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.612	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.610	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.610	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.607	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.607	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.605	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.605	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.602	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.602	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.595	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.595	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.592	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.592	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.589	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.589	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.587	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.587	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.585	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.584	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.582	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.582	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.580	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.580	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.577	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.577	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.569	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.569	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.567	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.567	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.564	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.564	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.562	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.562	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.560	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.560	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.557	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.557	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.555	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.555	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.552	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.552	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.544	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                javascript.0	2020-04-15 10:08:10.544	error	(834) script.js.java.sonstige.Heos_neu: [Heos] Error: This socket has been ended by the other party
                                javascript.0	2020-04-15 10:08:10.542	info	(834) script.js.java.sonstige.Heos_neu: [Heos] disconnecting from HEOS ...
                                

                                Änderung: Jetzt habe ich das neue Script in einer zweiten JS-Instanz auf dem Slave-System gestartet, und es funktioniert bisher problemfrei. Das beobachte ich mal.

                                Proxmox und HA

                                1 Antwort Letzte Antwort
                                0
                                • C Offline
                                  C Offline
                                  chrisblu
                                  schrieb am zuletzt editiert von
                                  #114

                                  @withstu Hi, das Skript läuft bei mir sehr schön stabil, thumbs up.
                                  Das einzige, was nicht immer klappt, ist der Start mit einem Neustart vom Broker.
                                  Von Zeit zu Zeit stoppe ich meinen Broker manuell, führe die Updates der Adapter durch und starte wieder.
                                  Dabei wird nicht immer das Heos-Skript neu gestartet. Manchmal bekomme ich die Meldung, dass der Socket beendet wurde:

                                  javascript.1	2020-04-20 07:33:11.020	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:32:56.020	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                  javascript.1	2020-04-20 07:32:56.019	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:32:41.018	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:32:26.029	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:32:11.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:31:56.018	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                  javascript.1	2020-04-20 07:31:56.017	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:31:41.017	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:31:26.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:31:11.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:56.016	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                  javascript.1	2020-04-20 07:30:56.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:41.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:26.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:11.014	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:06.030	info	(21921) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] starting HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                  javascript.1	2020-04-20 07:30:06.027	info	(21921) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] starting HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                  javascript.1	2020-04-20 07:30:06.023	info	(21921) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] starting HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                  javascript.1	2020-04-20 07:30:01.047	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:01.042	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:30:01.030	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                  javascript.1	2020-04-20 07:29:57.180	warn	(21921) script.js.Steuerung.heos: [Heos] HEOS closed the connection to 192.168.111.22
                                  javascript.1	2020-04-20 07:29:56.024	info	(21921) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] creating HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                  javascript.1	2020-04-20 07:29:56.023	info	(21921) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] creating HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                  javascript.1	2020-04-20 07:29:56.020	info	(21921) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] creating HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                  javascript.1	2020-04-20 07:29:56.010	info	(21921) script.js.Steuerung.heos: [Heos] connected to HEOS (192.168.111.22)
                                  javascript.1	2020-04-20 07:29:56.006	info	(21921) script.js.Steuerung.heos: [Heos] connecting to HEOS (192.168.111.22) ...
                                  javascript.1	2020-04-20 07:29:55.881	info	(21921) script.js.Steuerung.heos: registered 1 subscription and 0 schedules
                                  javascript.1	2020-04-20 07:29:55.715	info	(21921) script.js.Steuerung.heos: [Heos] searching for HEOS devices ...
                                  javascript.1	2020-04-20 07:29:55.641	info	(21921) Start javascript script.js.Steuerung.heos
                                  javascript.1	2020-04-20 07:29:55.162	info	(21921) received all states
                                  javascript.1	2020-04-20 07:29:55.114	info	(21921) received all objects
                                  javascript.1	2020-04-20 07:24:25.123	info	(27211) Terminated (START_IMMEDIATELY_AFTER_STOP): Without reason
                                  javascript.1	2020-04-20 07:24:24.989	info	(27211) Got terminate signal TERMINATE_YOURSELF
                                  javascript.1	2020-04-20 07:24:24.971	info	(27211) script.js.Steuerung.heos: [Heos] disconnected from HEOS
                                  javascript.1	2020-04-20 07:24:24.953	info	(27211) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] stopping HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                  javascript.1	2020-04-20 07:24:24.939	info	(27211) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] stopping HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                  javascript.1	2020-04-20 07:24:24.864	info	(27211) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] stopping HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                  javascript.1	2020-04-20 07:24:24.860	info	(27211) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Stop interval
                                  javascript.1	2020-04-20 07:24:24.857	info	(27211) script.js.Steuerung.heos: [Heos] disconnecting from HEOS ...
                                  javascript.1	2020-04-20 07:24:24.725	info	(27211) Stop script script.js.Steuerung.heos
                                  


                                  Nach einem weiteren Neustart des Javascript-Adapters startet das Skript dann normal.
                                  Ich könnte mir vorstellen, dass das Skript gestartet wird, bevor irgend eine Abhängigkeit geladen wurde?

                                  Ich verwende dein Skript vom 10. April, das trat aber bei der vorhergehenden Version auch schon auf.

                                  Viele Grüße
                                  Christian

                                  W 1 Antwort Letzte Antwort
                                  0
                                  • C chrisblu

                                    @withstu Hi, das Skript läuft bei mir sehr schön stabil, thumbs up.
                                    Das einzige, was nicht immer klappt, ist der Start mit einem Neustart vom Broker.
                                    Von Zeit zu Zeit stoppe ich meinen Broker manuell, führe die Updates der Adapter durch und starte wieder.
                                    Dabei wird nicht immer das Heos-Skript neu gestartet. Manchmal bekomme ich die Meldung, dass der Socket beendet wurde:

                                    javascript.1	2020-04-20 07:33:11.020	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:32:56.020	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                    javascript.1	2020-04-20 07:32:56.019	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:32:41.018	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:32:26.029	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:32:11.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:31:56.018	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                    javascript.1	2020-04-20 07:31:56.017	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:31:41.017	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:31:26.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:31:11.016	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:56.016	warn	(21921) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Retries exceeded
                                    javascript.1	2020-04-20 07:30:56.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:41.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:26.015	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:11.014	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:06.030	info	(21921) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] starting HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                    javascript.1	2020-04-20 07:30:06.027	info	(21921) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] starting HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                    javascript.1	2020-04-20 07:30:06.023	info	(21921) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] starting HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                    javascript.1	2020-04-20 07:30:01.047	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:01.042	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:30:01.030	error	(21921) script.js.Steuerung.heos: [Heos] Error: This socket has been ended by the other party
                                    javascript.1	2020-04-20 07:29:57.180	warn	(21921) script.js.Steuerung.heos: [Heos] HEOS closed the connection to 192.168.111.22
                                    javascript.1	2020-04-20 07:29:56.024	info	(21921) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] creating HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                    javascript.1	2020-04-20 07:29:56.023	info	(21921) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] creating HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                    javascript.1	2020-04-20 07:29:56.020	info	(21921) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] creating HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                    javascript.1	2020-04-20 07:29:56.010	info	(21921) script.js.Steuerung.heos: [Heos] connected to HEOS (192.168.111.22)
                                    javascript.1	2020-04-20 07:29:56.006	info	(21921) script.js.Steuerung.heos: [Heos] connecting to HEOS (192.168.111.22) ...
                                    javascript.1	2020-04-20 07:29:55.881	info	(21921) script.js.Steuerung.heos: registered 1 subscription and 0 schedules
                                    javascript.1	2020-04-20 07:29:55.715	info	(21921) script.js.Steuerung.heos: [Heos] searching for HEOS devices ...
                                    javascript.1	2020-04-20 07:29:55.641	info	(21921) Start javascript script.js.Steuerung.heos
                                    javascript.1	2020-04-20 07:29:55.162	info	(21921) received all states
                                    javascript.1	2020-04-20 07:29:55.114	info	(21921) received all objects
                                    javascript.1	2020-04-20 07:24:25.123	info	(27211) Terminated (START_IMMEDIATELY_AFTER_STOP): Without reason
                                    javascript.1	2020-04-20 07:24:24.989	info	(27211) Got terminate signal TERMINATE_YOURSELF
                                    javascript.1	2020-04-20 07:24:24.971	info	(27211) script.js.Steuerung.heos: [Heos] disconnected from HEOS
                                    javascript.1	2020-04-20 07:24:24.953	info	(27211) script.js.Steuerung.heos: [HeosPlayer xxxxxxxxxxx] stopping HEOS player with pid xxxxxxxxxxx (192.168.111.23)
                                    javascript.1	2020-04-20 07:24:24.939	info	(27211) script.js.Steuerung.heos: [HeosPlayer yyyyyyyyyyyy] stopping HEOS player with pid yyyyyyyyyyyy (192.168.111.20)
                                    javascript.1	2020-04-20 07:24:24.864	info	(27211) script.js.Steuerung.heos: [HeosPlayer zzzzzzzzzzz] stopping HEOS player with pid zzzzzzzzzzz (192.168.111.22)
                                    javascript.1	2020-04-20 07:24:24.860	info	(27211) script.js.Steuerung.heos: [Heos] [HEARTBEAT] Stop interval
                                    javascript.1	2020-04-20 07:24:24.857	info	(27211) script.js.Steuerung.heos: [Heos] disconnecting from HEOS ...
                                    javascript.1	2020-04-20 07:24:24.725	info	(27211) Stop script script.js.Steuerung.heos
                                    


                                    Nach einem weiteren Neustart des Javascript-Adapters startet das Skript dann normal.
                                    Ich könnte mir vorstellen, dass das Skript gestartet wird, bevor irgend eine Abhängigkeit geladen wurde?

                                    Ich verwende dein Skript vom 10. April, das trat aber bei der vorhergehenden Version auch schon auf.

                                    Viele Grüße
                                    Christian

                                    W Offline
                                    W Offline
                                    withstu
                                    schrieb am zuletzt editiert von
                                    #115

                                    @chrisblu Der Fehler ist mir am Wochenende auch aufgefallen. Konnte ihn aber nicht mehr reproduzieren. Ich habe aber auf Verdacht in der reconnect Methode die stateCONNECTED Prüfung rausgenommen. An der könnte es gelegen haben, dass das Script sich nicht sauber beendet hat: heos.js

                                    In dem Zug habe ich auch die Events für Shuffle und Repeat korrigiert. Die haben bis jetzt noch nie funktioniert. Zudem habe ich zwei Commands hinzugefügt, die alle Player gruppieren bzw. alle Gruppen auflösen. Vielleicht benötigt sie ja jemand:
                                    group/group_all
                                    group/ungroup_all

                                    1 Antwort Letzte Antwort
                                    0
                                    • C Offline
                                      C Offline
                                      chrisblu
                                      schrieb am zuletzt editiert von
                                      #116

                                      @withstu danke, ich habe es eingespielt und werde das Verhalten mal beobachten.
                                      Die group all und ungroup all finde ich sehr praktisch. Werden die in dem übergeordneten command angegeben oder bei dem command der einzelnen Boxen?
                                      Gibt es sowas wie wie ungroup all auch für play? Vor allem Pause all oder Stopp all wäre für mich interessant, weil ich einen Knopf neben der Haustür habe, mit dem ich alle HEOS auschalten kann.
                                      LG Christian

                                      W 1 Antwort Letzte Antwort
                                      0
                                      • C chrisblu

                                        @withstu danke, ich habe es eingespielt und werde das Verhalten mal beobachten.
                                        Die group all und ungroup all finde ich sehr praktisch. Werden die in dem übergeordneten command angegeben oder bei dem command der einzelnen Boxen?
                                        Gibt es sowas wie wie ungroup all auch für play? Vor allem Pause all oder Stopp all wäre für mich interessant, weil ich einen Knopf neben der Haustür habe, mit dem ich alle HEOS auschalten kann.
                                        LG Christian

                                        W Offline
                                        W Offline
                                        withstu
                                        schrieb am zuletzt editiert von withstu
                                        #117

                                        @chrisblu Gute Idee. Ich hatte das bisher über ein anderes Script gelöst und habe es nun integriert: heos.js Es gibt jetzt drei neuen Commands, die sich über den übergeordneten Command steuern lassen:

                                        "group/ungroup_all" : Löst alle Player Gruppen auf.
                                        "group/group_all" : Gruppiert alle Player in einer Gruppe.

                                        "player/cmd": Sendet den Command cmd an alle Player.

                                        Bsp:
                                        player/set_play_state&state=pause
                                        player/set_play_state&state=play
                                        player/set_play_state&state=stop

                                        C 1 Antwort Letzte Antwort
                                        0
                                        • W withstu

                                          @chrisblu Gute Idee. Ich hatte das bisher über ein anderes Script gelöst und habe es nun integriert: heos.js Es gibt jetzt drei neuen Commands, die sich über den übergeordneten Command steuern lassen:

                                          "group/ungroup_all" : Löst alle Player Gruppen auf.
                                          "group/group_all" : Gruppiert alle Player in einer Gruppe.

                                          "player/cmd": Sendet den Command cmd an alle Player.

                                          Bsp:
                                          player/set_play_state&state=pause
                                          player/set_play_state&state=play
                                          player/set_play_state&state=stop

                                          C Offline
                                          C Offline
                                          chrisblu
                                          schrieb am zuletzt editiert von
                                          #118

                                          @withstu Cool, das werde ich gleich mal ausprobieren. Vielen Dank.
                                          Zu deiner Info: Skript läuft seit der letzten Version stabil, Probleme beim Neustart sind bisher nicht mehr aufgetreten.
                                          Viele Grüße
                                          Christian

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


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          740

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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