Ankündigung

Einklappen
Keine Ankündigung bisher.

- √ - Neues Plugin: Logitech Squeezebox - Anregungen?

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • macflei
    antwortet
    Zitat von JuMi2006 Beitrag anzeigen
    Kurze Zwischenfrage, wo geb ich die IP des Servers ein ?
    plugin/squeezebox/__init__.py

    dort in der Zeile:
    Code:
    def __init__(self, smarthome, host='127.0.0.1', port=9090):

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Kurze Zwischenfrage, wo geb ich die IP des Servers ein ?

    Hier mal der Anfang meiner item.conf

    Code:
    [squeeze]
      squeezebox_playerid = 00:04:20:1f:92:c4
      [[Name]]
        type = str
        visu = yes
        squeezebox_send = <playerid> Bad {}   
        squeezebox_recv = <playerid> Bad    
      [[IP]]
        type = str
        visu = yes
        squeezebox_recv = player ip <playerid>   
      [[Signal_Strength]]
        type = num
        visu = yes
        squeezebox_recv = <playerid> signalstrength    
      [[Power]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> power {}
        squeezebox_recv = <playerid> prefset server power
        squeezebox_init = <playerid> power    
        
      [[Mute]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> mixer muting {}
        squeezebox_recv = <playerid> prefset server mute
        squeezebox_init = <playerid> mixer muting
      [[Volume]]
        type = num
        visu = yes
        squeezebox_send = <playerid> mixer volume {}
        squeezebox_recv = <playerid> prefset server volume
        squeezebox_init = <playerid> mixer volume    
      [[Volume_Up]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> button volup
      [[Volume_Down]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> button voldown
    Grüße

    Einen Kommentar schreiben:


  • macflei
    antwortet
    Zitat von Robert Beitrag anzeigen
    Kannst du den Fehler genauer beschreiben? Hört der Player auf zu spielen? Oder wird nur der Titel/Interpret falsch angezeigt?
    In der Anzeige steht dann gar nichts oder der vorherige Titel (ohne Umlaute).Ist unterschiedlich.Der Player spielt dabei weiter.
    Sämtliche Funktionen (Lauter, Leiser, vor, Zurück etc.) werden dann bei Betätigen nicht mehr ausgeführt.
    F5 bleibt erfolglos.
    Springt man dann (z.B. über das Webinterface oder "manuell") zu einem Titel ohne Umlaute muß man die Seite der Visu neu laden oder f5 drücken und es passt läuft wie gewohnt....bis zum nächsten Titel mit Umlaut

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Hi!

    Nein, hab ich noch nicht versucht. Bin (bisher) nicht so der Musikfan der zu Hause Alben hört.

    Kannst du den Fehler genauer beschreiben? Hört der Player auf zu spielen? Oder wird nur der Titel/Interpret falsch angezeigt?

    Versuche das noch zu fixen - dann geht es dieses Wochenende ins GIT.

    Grüße
    Robert

    Einen Kommentar schreiben:


  • macflei
    antwortet
    Hallo Robert,
    hab heute Vormittag noch 2 weitere Player mit Deinem Plugin eingebaut.
    Beim Radio ist es in der Tat scheinbar "nur" ein UTF-8 Problem gewesen.
    Hast Du auch mal ne Playlist von nem Album abgespielet oder "durchlaufen" lassen? Hier "hängt" sich die Bedienung bei mir bei jedem Song mit Umlauten noch auf.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Zitat von macflei Beitrag anzeigen
    Geile Arbeit..... Geiles Plugin.
    Habs zwar noch nicht zu 100% eigebaut. Aber Lauter, Leiser, Play, Vor, Zurück und Mute gehen bei mir schonmal perfekt.
    Außer...... das "bekannte Problem" mit Umlauten in Künstler- oder Songnamen bringt das Plugin bei der Bedienung ins Stocken.

    Hinterlegte Playlists (z.B. Radiosender) könnte man ja "vorläufig" via multimedia.station aufrufen.
    Hi!

    Danke dir!

    Songnamen sind schon gefixt - nimm bitte die angehängte Version. Da fehlte die Konvertierung von UTF-8.

    Was die Playlist angeht komm ich grad nicht mit - wie du richtig sagst geht vor/zurück. Aber eine neue Playlists geht momentan nur per fixem Boolean-Item (siehe Playlist_Load_Internetradio), da ich keine Möglichkeit kenne einen String auszuwählen?

    Achtung: Statt * wird nun für <playerid> die ID der jeweiligen Squeezebox gesetzt - wurde benötigt da manchmal die ID nicht nur an erster Stelle steht und mir * dann einfach zu gefährlich war.

    Code:
    #!/usr/bin/env python
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #########################################################################
    # Copyright 2013 Robert Budde                        [EMAIL="robert@projekt131.de"]robert@projekt131.de[/EMAIL]
    #########################################################################
    #  Squeezebox-Plugin for SmartHome.py.  [url=http://mknx.github.com/smarthome/]SmartHome.py - Overview[/url]
    #
    #  This plugin is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This plugin is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this plugin. If not, see <[url=http://www.gnu.org/licenses/]Licenses - GNU Project - Free Software Foundation (FSF)[/url]>.
    #########################################################################
    import logging
    import struct
    import time
    import urllib2
    import lib.my_asynchat
    import re
    logger = logging.getLogger('Squeezebox')
    class Squeezebox(lib.my_asynchat.AsynChat):
        def __init__(self, smarthome, host='127.0.0.1', port=9090):
            lib.my_asynchat.AsynChat.__init__(self, smarthome, host, port)
            self._sh = smarthome
            self._val = {}
            self._obj = {}
            self._init_cmds = []
            smarthome.monitor_connection(self)
        def _check_mac(self, mac):
            return re.match("[0-9a-f]{2}([:])[0-9a-f]{2}([URL="file://\\1"]\\1[/URL][0-9a-f]{2}){4}$", mac.lower())
        
        def _resolv_full_cmd(self, item, attr):
            # check if PlayerID wildcard is used
            if '<playerid>' in item.conf[attr]:
                # try to get from parent object
                parent_item = item.return_parent()
                if (parent_item != None) and ('squeezebox_playerid' in parent_item.conf) and self._check_mac(parent_item.conf['squeezebox_playerid']):
                    item.conf[attr] = item.conf[attr].replace('<playerid>', parent_item.conf['squeezebox_playerid'])
                else:
                    logger.warning("squeezebox: could not resolve playerid for {0} from parent item {1}".format(item, parent_item))
                    return None
            return item.conf[attr] 
        def parse_item(self, item):
            
            if 'squeezebox_recv' in item.conf:         
                cmd = self._resolv_full_cmd(item,'squeezebox_recv')
                if (cmd == None):
                    return None 
                
                logger.debug("squeezebox: {0} receives updates by \"{1}\"".format(item, cmd))
                if not cmd in self._val:
                    self._val[cmd] = {'items': [item], 'logics': []}
                else:
                    if not item in self._val[cmd]['items']:
                        self._val[cmd]['items'].append(item)
                if ('squeezebox_init' in item.conf):
                    cmd = self._resolv_full_cmd(item,'squeezebox_init')
                    if (cmd == None):
                        return None 
                    
                    logger.debug("squeezebox: {0} is initialized by \"{1}\"".format(item, cmd))
                    if not cmd in self._val:
                        self._val[cmd] = {'items': [item], 'logics': []}
                    else:
                        if not item in self._val[cmd]['items']:
                            self._val[cmd]['items'].append(item)
                            
                if not cmd in self._init_cmds:
                    self._init_cmds.append(cmd)
                
            if 'squeezebox_send' in item.conf:         
                cmd = self._resolv_full_cmd(item,'squeezebox_send')
                if (cmd == None):
                    return None 
                
                logger.debug("squeezebox: {0} is send to \"{1}\"".format(item, cmd))
                return self.update_item
            else:        
                return None
        def parse_logic(self, logic):
            pass
        def update_item(self, item, caller=None, source=None, dest=None):
            # be careful: as the server echoes ALL comands not using this will result in a loop
            if caller != 'LMS':
                cmd = self._resolv_full_cmd(item, 'squeezebox_send').split()
                if self._check_mac(cmd[0]):
                    cmd[0] = urllib2.quote(cmd[0]) 
                if isinstance(item(), str):
                    value = urllib2.quote(item().encode('utf-8'))
                elif (item._type == 'bool'):
                    # convert to get '0'/'1' instead of 'True'/'False'
                    value = int(item()) 
                else:
                    value = item()
                    
                # special handling
                if (len(cmd) >= 2):
                    if (cmd[1] == 'play') and not item():
                        # if 'play' was set to false, send 'stop' to allow single-item-operation
                        cmd[1] = 'stop'
                        value = '1'
                    elif (cmd[1] == 'pause') and not item():
                        # squeezebox un-mutes when un-pausing but does not update the state itself - unmute manually to reflect actual state correctly
                        self._send(cmd[0] + ' mixer muting 0')
                        
                self._send(' '.join(cmd_str for cmd_str in cmd).format(value))
                  
        def _send(self, cmd):
            logger.debug("Sending request: {0}".format(cmd))
            self.push(cmd+'\r\n')
        def _parse_response(self, response):
            data = [urllib2.unquote(data_str) for data_str in response.split()]
            logger.debug("Got: {0}".format(data))
            
    #        if (data[0].lower() == 'player'):
    #            if (data[1].lower() == 'count'):
    #                num_players = int(data[2])
    #                logger.info("Found {0} player".format(num_players))
    #                for i in range(0,num_players):
    #                    self._send("player name {0} ?".format(i))
    #                    self._send("player id {0} ?".format(i))                    
    #            elif (data[1].lower() == 'name'):
    #                logger.info("Players {0} name is: {1}".format(data[2], data[3]))
    #            elif (data[1].lower() == 'id'):
    #                logger.info("Players {0} id is: {1}".format(data[2], data[3]))
            if (data[0].lower() == 'listen'):
                value = int(data[1]) 
                if (value == 1):
                    logger.info("Listen-mode enabled")
                else:
                    logger.info("Listen-mode disabled")
            if self._check_mac(data[0]):
                if (data[1] == 'play'):
                    self._update_items_with_data([data[0], 'play', 1])
                    self._update_items_with_data([data[0], 'stop', 0])
                    self._update_items_with_data([data[0], 'pause', 0])
                    # play also overrules mute
                    self._update_items_with_data([data[0], 'prefset server mute', 0])
                    return
                elif (data[1] == 'stop'):
                    self._update_items_with_data([data[0], 'play', 0])
                    self._update_items_with_data([data[0], 'stop', 1])
                    self._update_items_with_data([data[0], 'pause', 0])
                    return
                elif (data[1] == 'pause'):
                    self._send(data[0] + ' mode ?')
                    self._send(data[0] + ' mixer muting ?')
                    return
                elif (data[1] == 'mode'):
                    self._update_items_with_data([data[0], 'play', data[2] == 'play'])
                    self._update_items_with_data([data[0], 'stop', data[2] == 'stop'])
                    self._update_items_with_data([data[0], 'pause', data[2] == 'pause'])
                    # play also overrules mute
                    return
                elif (data[1] == 'prefset'):
                    if (data[2] == 'server'):
                        if (data[3] == 'volume'):
                            # make sure value is always positive - also if muted!
                            data[4] = abs(int(data[4]))
                elif (data[1] == 'playlist'):
                    if (data[2] == 'newsong'):
                        # trigger reading of other song fields
                        for field in ['genre', 'artist', 'album', 'title', 'duration']:
                            self._send(data[0] + ' ' + field + ' ?')
                elif (data[1] in ['genre', 'artist', 'album', 'title', 'duration']) and (len(data) == 2):
                    # these fields are returned empty so no update takes plase - append '' to trigger update
                    data.append('')           
                    
            self._update_items_with_data(data)
                                    
        def _update_items_with_data(self, data):        
            cmd = ' '.join(data_str for data_str in data[:-1])
            if (cmd in self._val):
                for item in self._val[cmd]['items']:
                    if isinstance(item(), str):
                        data[-1] = data[-1].decode('utf-8')            
                    item(data[-1], 'LMS', "{}:{}".format(self.addr[0],self.addr[1]))
                     
        def found_terminator(self):
            response = self.buffer
            self.buffer = ''
            self._parse_response(response)
        def handle_connect(self):
            self.discard_buffers()
            # start discovering players and their respective IDs and names        
    #        self._send('players 0')
            self._send('listen 1')
            if self._init_cmds != []:
                if self.is_connected:
                    logger.debug('squeezebox: init read')
                    for cmd in self._init_cmds:
                        self._send(cmd+' ?')
            
        def run(self):
            self.alive = True
        def stop(self):
            self.alive = False
            self.handle_close()
    Code:
    # Hobbyraum/Experimental
    [Squeezebox_1]
      squeezebox_playerid = 00:04:20:xx:xx:xx
      [[Name]]
        type = str
        visu = yes
        squeezebox_send = <playerid> name {}   
        squeezebox_recv = <playerid> name    
      [[IP]]
        type = str
        visu = yes
        squeezebox_recv = player ip <playerid>   
      [[Signal_Strength]]
        type = num
        visu = yes
        squeezebox_recv = <playerid> signalstrength    
      [[Power]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> power {}
        squeezebox_recv = <playerid> prefset server power
        squeezebox_init = <playerid> power    
        
      [[Mute]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> mixer muting {}
        squeezebox_recv = <playerid> prefset server mute
        squeezebox_init = <playerid> mixer muting
      [[Volume]]
        type = num
        visu = yes
        squeezebox_send = <playerid> mixer volume {}
        squeezebox_recv = <playerid> prefset server volume
        squeezebox_init = <playerid> mixer volume    
      [[Volume_Up]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> button volup
      [[Volume_Down]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> button voldown
        
      [[Play]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> play
        squeezebox_recv = <playerid> play
        squeezebox_init = <playerid> mode
      [[Stop]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> stop
        squeezebox_recv = <playerid> stop
        squeezebox_init = <playerid> mode
      [[Pause]]
        type = bool
        visu = yes
        squeezebox_send = <playerid> pause {}
        squeezebox_recv = <playerid> pause
        squeezebox_init = <playerid> mode
     
      [[Current_Title]]
        type = str
        visu = yes
        squeezebox_recv = <playerid> playlist newsong
        squeezebox_init = <playerid> current_title
      [[Genre]]
        type = str
        visu = yes
        squeezebox_recv = <playerid> genre
      [[Artist]]
        type = str
        visu = yes
        squeezebox_recv = <playerid> artist
      [[Album]]
        type = str
        visu = yes
        squeezebox_recv = <playerid> album
      [[Title]]
        type = str
        visu = yes
        squeezebox_recv = <playerid> title
      [[Duration]]
        type = num
        visu = yes
        squeezebox_recv = <playerid> duration
      [[Playlist_Index]]
        type = num
        visu = yes
        squeezebox_send = <playerid> playlist index {}
        squeezebox_recv = <playerid> playlist index
      [[Playlist_Forward]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> playlist index +1
      [[Playlist_Backward]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> playlist index -1
        
      [[Playlist_Name]]
        type = str
        visu = yes
        squeezebox_send = <playerid> playlist name {}
        squeezebox_recv = <playerid> playlist name
      [[Playlist_Save]]
        type = str
        visu = yes
        squeezebox_send = <playerid> playlist save {}   
      [[Playlist_Load]]
        type = str
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> playlist play {}
      [[Playlist_Load_Internetradio]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = <playerid> playlist play [URL]file:///home/robert/playlists/Internetradio.m3u[/URL]

    Einen Kommentar schreiben:


  • macflei
    antwortet
    Geile Arbeit..... Geiles Plugin.
    Habs zwar noch nicht zu 100% eigebaut. Aber Lauter, Leiser, Play, Vor, Zurück und Mute gehen bei mir schonmal perfekt.
    Außer...... das "bekannte Problem" mit Umlauten in Künstler- oder Songnamen bringt das Plugin bei der Bedienung ins Stocken.

    Hinterlegte Playlists (z.B. Radiosender) könnte man ja "vorläufig" via multimedia.station aufrufen.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Sag mir vorher Bescheid, hab das Plugin noch ein wenig verfeinert (IP und Name wurden u.A. noch falsch ausgelesen bei mehreren Boxen)

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Neee ... hätte ich auch so gemacht ... wie gesagt ... Zeit oh Zeit ... vielleicht schmeiß ich zum testen mal den LMS auf meinen (noch Windows) HomeServer.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Hi Mirko,

    ja, das ist korrekt. Man könnte wohl auch selektiv mit "subscribe" arbeiten, aber in meinen Augen macht das angesichts der wohl üblicherweise verlangten Informationen keinen Sinn.

    Grüße
    Robert

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Sobald wieder mehr Zeit ist werde ich das testen ... momentan zu viele Baustellen ... sieht aber sauber aus ... du arbeitest auch mit dem "listen" via telnet um den Status der Squeeze aktuell zu halten wenn ich das richtig interpretiere (bin da nur kurz drübergeflogen) ?

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Nachtrag:

    Hab gerade in der Docu-Visu geguckt: "popup3" wäre als Basis Klasse! Allerdings weiß ich nicht, wie ich da eine dynamische Liste reinbringe? Sonst ginge ja nur (z.B.) 5 Items für die ersten 5 Playlisten die dann über einen Button ausgewählt werden könnten. Wäre etwas umständlich und halt von der Anzahl limitiert und unübersichtlich (sowohl item.conf als auch in der Visu-Erstellung).

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Zitat von Apollo Beitrag anzeigen
    falls du "optisch" was brauchst, einfach melden
    Hallo Martin,

    wo du das so sagst... *fg*

    Die Optik des Players ist momentan quasi eine Kopie von Axel Otterstätter "multimedia.music". Da habe ich nur die Sachen angepasst die nicht zu den Items der Squeezebox passen. Wenn alle Features mal fix sind, kann da vielleicht jemand der kreativer als ich ist Hand anlegen.

    Was für mich momentan interessant wäre:

    "Oben rechts" ist momentan der Playlisten-Button, welcher die Standard-Playliste (bei mir "Internetradio") lädt. Schöner wäre es natürlich, wenn sich ein Popup öffnen würde, welches die verfügbaren Playlisten anzeigt (dynamisch, vl. 5 direkt, sonst zum scrollen?). Wenn man dann eine auswählt wird diese geladen.

    Ich könnte ein Item erstellen ("* playlists 0 99"), welches alle Playlisten zurückgeben würde. Evtl. kann man das umformatieren, denn momentan kommt dann:
    Code:
    id=1823 playlist=Internetradio id=1824 playlist=Test2 id=1825 playlist=Test3 Count=3
    Was für ein Format bräuchte so eine Liste? Popup Möglich?

    <bei Klick öffne Popup mit diesen Auswahl-Items ("gad_list") und erlaube schließen ohne Auswahl oder Auswahl mit Rückgabe Item ("gad_select")>

    Sowas könnte man wohl auch an noch mehr Stellen einsetzen (Songauswahl, Nachrichten, Stati setzen etc.).

    Grüße
    Robert

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Hi!

    Danke dir! Das mit dem Abspeichern und Laden einer Playliste scheint dann also der Weg zu sein. Lautstärke wäre dann ja in der Tat genauso: Vorher abspeichern, hinterher wiederherstellen. Ist dann wahrscheinlich eher was für eine "Logik" als für das Plugin.

    Folgende Items funktionieren jetzt auch (ohne Änderungen am Plugin!):
    Code:
      [[Playlist_Index]]
        type = num
        visu = yes
        squeezebox_send = * playlist index {}
        squeezebox_recv = * playlist index
      [[Playlist_Forward]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = * playlist index +1
      [[Playlist_Backward]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = * playlist index -1
        
      [[Playlist_Name]]
        type = str
        visu = yes
        squeezebox_send = * playlist name {}
        squeezebox_recv = * playlist name
      [[Playlist_Save]]
        type = str
        visu = yes
        squeezebox_send = * playlist save {}   
      [[Playlist_Load]]
        type = str
        enforce_updates = true
        visu = yes
        squeezebox_send = * playlist play {}
      [[Playlist_Load_Internetradio]]
        type = bool
        enforce_updates = true
        visu = yes
        squeezebox_send = * playlist play [URL]file:///home/robert/playlists/Internetradio.m3u[/URL]
    Damit müsste es jetzt auch Alarmierungen möglich sein.

    Einen Kommentar schreiben:


  • Apollo
    antwortet
    Hallo Robert!

    +1

    falls du "optisch" was brauchst, einfach melden

    Gruss

    Einen Kommentar schreiben:

Lädt...
X