SmartHomeNG - Plugin Squeezebox


Dieses Beispiel muss überarbeitet werden, da sich die verwendeten Widgets mit v3.0 geändert haben. Neue Widgets sind in Erstellung. Deshalb hier noch die alte Beschreibung als Orientierung.



Hier ein Beispiel wie man den Squeezebox-Server und Squeezebox-Player in die Visu einbinden kann und diesen über die Visu und somit auch z.B. über Tastsensoren steuern kann. Für die Darstellung des Players in der Visu nutzen wir ein "eigenes" Widget, welches Robert Budde aus dem KNX-Userforum auf Basis des "multimedia.musik"-Widget von Axel Oberstätter erstellt hat. Vielen Dank dafür.

1. Plugin einbinden:

Zu Beginn binden wir den SB(Squeezebox)-Server ein. Das benötigte Plugin liefert SmartHomeNG und wir müssen es nur noch in die plugin.yaml einfügen. Diese finden wir unter
/usr/smarthome/etc/plugin.yaml
Hier fügen wir nun folgendes ein: hierbei bedarf es nun 2 Anpassungen:
  • host - Die IP unter welcher der SB-Server zu erreichen ist
  • port - Der Port unter welcher der SB-Server zu erreichen ist (Standart = 9090)
Dann die plugin.yaml speichern.

2. Items erstellen:

Als nächstes erstellen wir die Items. Dazu erstellen wir im Item-Verzeichnis via WinSCP eine Datei und nennen diese der Einfachheit halber squeezebox.yaml
In diese Datei fügen wir nun folgenden kompletten Inhalt und speichern diese anschließend. !!! Die im Code aufgeführte Mac-Adresse (squeezebox_playerid) ist anzupassen !!!

squeezebox.yaml

Squeezebox_Player1:
    squeezebox_playerid: 00:04:20:2a:87:b7

    Name:
        type: str
        visu_acl: rw
        squeezebox_send: ' name {}'
        squeezebox_recv: ' name'

    IP:
        type: str
        visu_acl: rw
        squeezebox_recv: player ip 

    Signal_Strength:
        type: num
        visu_acl: rw
        squeezebox_recv: ' signalstrength'

    Power:
        type: bool
        visu_acl: rw
        squeezebox_send: ' power {}'
        squeezebox_recv: ' prefset server power'
        squeezebox_init: ' power'

    Mute:
        type: bool
        visu_acl: rw
        squeezebox_send: ' mixer muting {}'
        squeezebox_recv: ' prefset server mute'
        squeezebox_init: ' mixer muting'

    Volume:
        type: num
        visu_acl: rw
        squeezebox_send: ' mixer volume {}'
        squeezebox_recv: ' prefset server volume'
        squeezebox_init: ' mixer volume'

    Volume_Up:
        type: bool
        enforce_updates: 'true'
        visu_acl: rw
        squeezebox_send: ' button volup'

    Volume_Down:
        type: bool
        enforce_updates: 'true'
        visu_acl: rw
        squeezebox_send: ' button voldown'

    Play:
        type: bool
        visu_acl: rw
        squeezebox_send: ' play'
        squeezebox_recv: ' play'
        squeezebox_init: ' mode'

    Stop:
        type: bool
        visu_acl: rw
        squeezebox_send: ' stop'
        squeezebox_recv: ' stop'
        squeezebox_init: ' mode'

    Pause:
        type: bool
        visu_acl: rw
        squeezebox_send: ' pause {}'
        squeezebox_recv: ' pause'
        squeezebox_init: ' mode'

    Repeat:
        type: num
        visu_acl: rw
        enforce_updates: yes
        squeezebox_send: ' playlist repeat {}'
        squeezebox_recv: ' playlist repeat'

    Repeat_Song:
        type: bool
        visu_acl: rw
        enforce_updates: yes
        squeezebox_send: ' playlist repeat 1'

    Repeat_Playlist:
        type: bool
        visu_acl: rw
        enforce_updates: yes
        squeezebox_send: ' playlist repeat 2'

    Repeat_None:
        type: bool
        visu_acl: rw
        enforce_updates: yes
        squeezebox_send: ' playlist repeat 0'

    Current_Title:
        type: str
        visu_acl: rw
        squeezebox_recv: ' playlist newsong'
        squeezebox_init: ' current_title'

    Genre:
        type: str
        visu_acl: rw
        squeezebox_recv: ' genre'

    Artist:
        type: str
        visu_acl: rw
        squeezebox_recv: ' artist'

    Album:
        type: str
        visu_acl: rw
        squeezebox_recv: ' album'

    Title:
        type: str
        visu_acl: rw
        squeezebox_recv: ' title'

    Duration:
        type: num
        visu_acl: rw
        squeezebox_recv: ' duration'

    Time:
        type: num
        visu_acl: rw
        squeezebox_recv: ' playlist time'

    TimePlus:
        type: num
        visu_acl: rw
        enforce_updates: 'true'
        squeezebox_recv: ' time'
        squeezebox_send: ' time +10'

    TimeMinus:
        type: num
        visu_acl: rw
        enforce_updates: 'true'
        squeezebox_recv: ' time'
        squeezebox_send: ' time -10'

    Playlist_Index:
        type: num
        visu_acl: rw
        squeezebox_send: ' playlist index {}'
        squeezebox_recv: ' playlist index'

    Playlist_Forward:
        type: bool
        enforce_updates: 'true'
        visu_acl: rw
        squeezebox_send: ' playlist index +1'

    Playlist_Backward:
        type: bool
        enforce_updates: 'true'
        visu_acl: rw
        squeezebox_send: ' playlist index -1'

    Playlist_Name:
        type: str
        visu_acl: rw
        squeezebox_send: ' playlist name {}'
        squeezebox_recv: ' playlist name'

    Playlist_Save:
        type: str
        visu_acl: rw
        squeezebox_send: ' playlist save {}'

    Playlist_Load:
        type: str
        enforce_updates: 'true'
        visu_acl: rw
        squeezebox_send: ' playlist play {}'


3. Widget einbinden:

Wie oben bereits erwähnt nutzen wir hier mal nicht ein Standart-Widget sondern ein angepasstes Widget. Dazu erstellen wir uns in unserem Pages-Verzeichnis im Unterordner /widgets zwei neue Dateien mit den Namen widget_squeezebox.html und widget_my.html.

In die widget_squeezebox.html fügen wir folgendes ein:

widget_squeezebox.html

/** 
* ----------------------------------------------------------------------------- 
* @package     smartVISU 
* @author      Martin Gleiß 
* @copyright   2012 
* @license     GPL  
* ----------------------------------------------------------------------------- 
*/ 
 
/** 
* Squeezebox Multimedia Player 
*  
* @param       unique id for this widget 
* @param       the gad/item for play 
* @param       the gad/item for pause 
* @param       the gad/item for stop (optional) 
* @param       the gad/item for playlist forward 
* @param       the gad/item for playlist backward 
* @param       the gad/item for playlist fastforward (opuional) 
* @param       the gad/item for playlist fastbackward (opuional) 
* @param       the gad/item for the volume (optional) 
* @param       the gad/item to mute the music (optional) 
* @param       the gad/item for the song title (optional) 
* @param       the gad/item for the song artist (optional) 
* @param       the gad/item for repeat (optional) 
* @param       the gad/item to repeat all (optional) 
* @param       the gad/item for the duration (optional) 
* @param       the gad/item for the time/position (optional) 
* @param       the gad/item for the playlist index (optional) 
* @param       the gad/item for the playlist total (optional) 
* 
* @author      Robert Budde 
* derived from "multimedia" by Axel Otterstätter - thanks! 
*/ 
{% macro control(id, gad_power, gad_play, gad_pause, gad_stop, gad_playlistforward, gad_playlistbackward, gad_playlistfastforward, gad_playlistfastbackward, gad_vol, gad_mute, gad_title, gad_artist, gad_repeat, gad_repeatall, gad_defaultplaylist, gad_duration, gad_time) %} 
   {% import config_version_full >= "3.2.c" ? "@widgets/basic.html" : "basic.html" as basic %}
   {% import config_version_full >= "3.2.c" ? "@widgets/widget_my.html" : "widget_my.html" as my %}
   {% set uid = uid(page, id) %} 
 
   <div id="{{ uid }}" class="music"> 
        
       {% if gad_vol %} 
       <div class="vol"> 
           <img class="slider-bottomup-scale" src="pages/base/pics/scale_buttomup.png"> 
           {{ basic.slider(id~'vol', gad_vol, 0, 100, 5, 'bottomup') }} 
       </div> 
       {% endif %} 
 
 
       <div class="control"> 
       {% if gad_power %} {{ basic.dual(id~'power', gad_power, icon1~'control_standby.svg', icon0~'control_standby.svg') }} {% endif %} 
       {% if gad_mute %} {{ basic.dual(id~'mute', gad_mute, icon1~'audio_volume_mute.svg', icon0~'audio_volume_mute.svg', 1, 0) }} {% endif %} 
       {% if gad_repeat %} {{ basic.dual(id~'repeat', gad_repeat, icon1~'control_return.svg', icon0~'control_return.svg', 1, 0) }} {% endif %} 
       {% if gad_repeatall %} {{ basic.dual(id~'repeatall', gad_repeatall, icon1~'audio_repeat.svg', icon0~'audio_repeat.svg') }} {% endif %} 
       {% if gad_defaultplaylist %} {{ basic.button(id~'defaultplaylist', gad_defaultplaylist, 'Default Playlist', icon0~'audio_playlist.svg', 1) }} {% endif %} 
       </div> 
 
       <div class="title"> 
         {% if gad_artist %} 
         {{ basic.value(id~'artist', gad_artist) }} 
         <br /> 
         {% endif %} 
         {% if gad_title %} 
         {{ basic.value(id~'title', gad_title) }} 
         {% endif %} 
         <br /> 
         {% if gad_playlistist %} 
         {% if gad_playlisttotal %} 
         {{ basic.value(id~'playlistist', gad_playlistist) }} von {{ basic.value(id~'playlisttotal', gad_playlisttotal) }} 
         {% endif %} 
         {% endif %} 
       </div> 
 
       <div class="set"> 
           {% if gad_duration %} 
           {% if gad_time %} 
           <div class="pos"> 
               <div class="scale">&nbsp; 
               {{ my.time_slider(id~'time', gad_time, gad_duration, 1) }} 
           </div> 
           {% endif %} 
           {% endif %} 
 
           <div data-role="controlgroup" data-type="horizontal"> 
               {{ basic.dual(id~'play', gad_play, icon1~'audio_play.svg', icon0~'audio_play.svg', 1, 1) }} 
               {{ basic.dual(id~'pause', gad_pause, icon1~'audio_pause.svg', icon0~'audio_pause.svg') }} 
               {% if gad_stop %} {{ basic.dual(id~'stop', gad_stop, icon1~'audio_stop.svg', icon0~'audio_stop.svg', 1, 1) }} {% endif %} 
          </div> 
           <div data-role="controlgroup" data-type="horizontal"> 
               {{ basic.button(id~'playlistbackward', gad_playlistbackward, 'backward', icon0~'control_arrow_left.svg', 1) }} 
               {% if gad_playlistfastbackward %} {{ basic.button(id~'gad_playlistfastbackward', gad_playlistfastbackward, 'fastbackward', icon0~'control_arrow_leftward.svg', 1) }} {% endif %} 
               {% if gad_playlistfastforward %} {{ basic.button(id~'playlistfastforward', gad_playlistfastforward, 'fastforward', icon0~'control_arrow_rightward.svg', 1) }} {% endif %} 
               {{ basic.button(id~'playlistforward', gad_playlistforward, 'forward', icon0~'control_arrow_right.svg', 1) }} 
          </div> 
      </div> 
   </div> 
{% endmacro %}

				

In die widget_my.html fügen wir folgendes ein:

widget_my.html

	
/** * A list with selectable item * * @param unique id for this widget * @param a gad/item for the list * @param a gad/item for the selected item * @param the text to be displayed on top of the list */ {% macro list(id, gad_list, gad_item, txt ) %} <ul id="{{ uid(page, id) }}" data-widget="basic.list" data-item="{{ gad_list }}, {{ gad_item }}" data-role="listview" data-dividertheme="c"> <li data-icon="false"><a href="#">View details</a></li> <li data-icon="false"><a href="#">Edit</a></li> <li data-icon="false"><a href="#">Disable</a></li> <li data-icon="false"><a href="#">Delete</a></li> </ul> {% endmacro %} /** * Displays a slider-control * * @param unique id for this widget * @param a gad/item current time (progress) * @param a gad/item total duration (maximum) * @param seconds between two values (optional, default 5s) * @param the orientation ('none', 'vertical', 'bottomup', 'semicircle') */ {% macro time_slider(id, gad_time, gad_duration, step, mode) %} <input id="{{ uid(page, id) }}" data-widget="my.time_slider" data-item="{{ gad_time }}, {{ gad_duration }}" type="range" value="0" min="0" max="1" disabled="1" step="{{ step|default(5) }}" orientation="{{ mode }}" data-highlight="true" /> {% endmacro %}

Da unser "eigenes" Widget bereits in einem für Widgets reservierten Ordner liegt, wird es beim Laden der Seite automatisch importiert. Das Widget kann dann in der html-Seite an beliebiger Stelle aufgerufen werden:
{{ squeezebox.control('music1', 'Squeezebox_Player1.Power', 'Squeezebox_Player1.Play', 'Squeezebox_Player1.Pause', 'Squeezebox_Player1.Stop', 'Squeezebox_Player1.Playlist_Forward', 'Squeezebox_Player1.Playlist_Backward', 'Squeezebox_Player1.TimePlus', 'Squeezebox_Player1.TimeMinus', 'Squeezebox_Player1.Volume', 'Squeezebox_Player1.Mute', 'Squeezebox_Player1.Title', 'Squeezebox_Player1.Artist', 'Squeezebox_Player1.Repeat', 'Squeezebox_Player1.Repeat_Playlist', '', 'Squeezebox_Player1.Duration', '') }}

Playlists


Wer mag, kann sich beispielsweise mit GIMP eigene Icons für Cover oder Radiosender erzeugen. In diesem Beispiel wurden diese als *.png gespeichert und unter folgendem Verzeichnis abgelegt.
./pics/station/Playlists/

Weiterhin benötigen wir wieder unsere Items. Ein Beispielitem mit Pfad zur hinterlegten Playlist könnte so aussehen:
Das verwendete Widgets ist "multimedia.station". Beispiel:
{{ multimedia.station('Playlist1', 'Squeezebox_Player1.Playlist_Load_AntenneBayern','pics/station/playlists/antennebayern.png', 1, 'midi') }}

Nun haben wir verschiedene Möglichkeiten, wo wir die Playlist aufrufen können. Hier mal 2 Beispiele. Einmal als eigenständiger Block und einmal zusammen mit dem Player in einem Block Typ 3. Beginnen wir mit dem eigenständigen Block.

Playlisten

------ Radio ------

----- Alben -----

hier jetzt das dazugehörige html-Beispiel:

Beispiel html (Klick mich)



Und hier noch das Beispiel in Verbindung mit dem Player in einem Block Typ 3

Playlisten

------ Radio ------

----- Alben -----

hier jetzt das dazugehörige html-Beispiel:

Beispiel html (Klick mich)