From f7f1552d9fbae2ad70f37ca3477d9316956e4719 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Mon, 29 Jan 2018 08:39:26 -0500 Subject: [PATCH 01/14] Add favoriteList/favoritesPlay channel to Server/Player Signed-off-by: Mark Hilbush --- .../ESH-INF/thing/thing-types.xml | 32 +++- .../org.openhab.binding.squeezebox/README.md | 59 ++++--- .../SqueezeBoxBindingConstants.java | 6 +- .../handler/SqueezeBoxPlayerHandler.java | 3 + .../handler/SqueezeBoxServerHandler.java | 144 +++++++++++++++++- .../config/SqueezeBoxServerConfig.java | 4 + .../squeezebox/internal/model/Favorite.java | 52 +++++++ 7 files changed, 268 insertions(+), 32 deletions(-) create mode 100644 addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java diff --git a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml index d5af88d591c26..fac7535570614 100644 --- a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml +++ b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml @@ -5,8 +5,12 @@ - This is a SqueezeBox Server instance. - + This is a SqueezeBox Server instance. + + + + + @@ -37,6 +41,11 @@ Password used to login to Squeeze Server password + + + Wrap the right hand side of the favorites in quotes + false + @@ -44,8 +53,10 @@ + This is a SqueezeBox Player instance + @@ -73,7 +84,9 @@ + + Logitech @@ -81,6 +94,7 @@ + @@ -89,6 +103,20 @@ + + + String + + Comma-separated list of favorites of form favoriteId=favoriteName + + + + String + + Play favorite by sending command with favoriteId + + + Switch diff --git a/addons/binding/org.openhab.binding.squeezebox/README.md b/addons/binding/org.openhab.binding.squeezebox/README.md index 1becf45886097..1f5a04ba5b98a 100644 --- a/addons/binding/org.openhab.binding.squeezebox/README.md +++ b/addons/binding/org.openhab.binding.squeezebox/README.md @@ -48,39 +48,48 @@ Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport= Or, if Squeeze Server authentication is enabled: ``` -Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport=9000, cliport=9090, userId="yourid", password="yourpassword" ] +Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport=9000, cliport=9090, userId="yourid", password="yourpassword", quoteFavoritesList=true ] { Thing squeezeboxplayer myplayer[ mac="00:f1:bb:00:00:f1" ] } ``` -## Channels +## Server Channels + +The Squeezebox server supports the following channel: + +| Channel Type ID | Item Type | Description | +|-------------------------|-----------|----------------------------------------------------------------------------------------| +| favoritesList | String | Comma-separated list of favorite IDs & names, updated whenever list changes on server | + +## Player Channels All devices support some of the following channels: -| Channel Type ID | Item Type | Description | | | -|-------------------------|-----------|----------------------------------------------------------------------------------------|----------------------|---| -| power | Switch | Power on/off your device | | | -| mute | Switch | Mute/unmute your device | | | -| volume | Dimmer | Volume of your device | | | -| stop | Switch | Stop the current title | | | -| control | Player | Control the Zone Player, e.g. play/pause/next/previous/ffward/rewind | | | -| stream | String | Play the given HTTP or file stream (file:// or http://) | | | -| sync | String | Add another player to your device for synchronized playback (other player mac address) | | | -| playListIndex | Number | Playlist Index | | | -| currentPlayingTime | | Number | Current Playing Time | | -| currentPlaylistShuffle | Number | Current playlist shuffle mode (0 No Shuffle, 1 Shuffle Songs, 2 Shuffle Albums) | | | -| currentPlaylistRepeat | Number | Current playlist repeat Mode (0 No Repeat, 1 Repeat Song, 2 Repeat Playlist) | | | -| title | String | Title of the current song | | | -| remotetitle | String | Remote Title (Radio) of the current song | | | -| album | String | Album name of the current song | | | -| artist | String | Artist name of the current song | | | -| year | String | Release year of the current song | | | -| genre | String | Genre name of the current song | | | -| coverartdata | Image | Image data of cover art of the current song | | | -| ircode | String | Received IR code | | | -| numberPlaylistTracks | Number | Number of playlist tracks | | | -| notificationSoundVolume | Dimmer | Volume for playing notifications | | | +| Channel Type ID | Item Type | Description | +|-------------------------|-----------|----------------------------------------------------------------------------------------| +| power | Switch | Power on/off your device | +| mute | Switch | Mute/unmute your device | +| volume | Dimmer | Volume of your device | +| stop | Switch | Stop the current title | +| control | Player | Control the Zone Player, e.g. play/pause/next/previous/ffward/rewind | +| stream | String | Play the given HTTP or file stream (file:// or http://) | +| sync | String | Add another player to your device for synchronized playback (other player mac address) | +| playListIndex | Number | Playlist Index | +| currentPlayingTime | Number | Current Playing Time | +| currentPlaylistShuffle | Number | Current playlist shuffle mode (0 No Shuffle, 1 Shuffle Songs, 2 Shuffle Albums) | +| currentPlaylistRepeat | Number | Current playlist repeat Mode (0 No Repeat, 1 Repeat Song, 2 Repeat Playlist) | +| title | String | Title of the current song | +| remotetitle | String | Remote Title (Radio) of the current song | +| album | String | Album name of the current song | +| artist | String | Artist name of the current song | +| year | String | Release year of the current song | +| genre | String | Genre name of the current song | +| coverartdata | Image | Image data of cover art of the current song | +| ircode | String | Received IR code | +| numberPlaylistTracks | Number | Number of playlist tracks | +| notificationSoundVolume | Dimmer | Volume for playing notifications | +| favoritesPlay | String | ID of Favorite to play (as available in server's favoritesList channel) | ## Notifications diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java index d12f947c816a0..fe11c6b32a2a7 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java @@ -25,7 +25,10 @@ public class SqueezeBoxBindingConstants { public static final ThingTypeUID SQUEEZEBOXPLAYER_THING_TYPE = new ThingTypeUID(BINDING_ID, "squeezeboxplayer"); public static final ThingTypeUID SQUEEZEBOXSERVER_THING_TYPE = new ThingTypeUID(BINDING_ID, "squeezeboxserver"); - // List of all Channel ids + // List of all Server Channel Ids + public static final String CHANNEL_FAVORITES_LIST = "favoritesList"; + + // List of all Player Channel Ids public static final String CHANNEL_POWER = "power"; public static final String CHANNEL_MUTE = "mute"; public static final String CHANNEL_VOLUME = "volume"; @@ -57,4 +60,5 @@ public class SqueezeBoxBindingConstants { public static final String CHANNEL_NAME = "name"; public static final String CHANNEL_MODEL = "model"; public static final String CHANNEL_NOTIFICATION_SOUND_VOLUME = "notificationSoundVolume"; + public static final String CHANNEL_FAVORITES_PLAY = "favoritesPlay"; } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 8944c54d21961..3eb8473bcd20b 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -277,6 +277,9 @@ public void handleCommand(ChannelUID channelUID, Command command) { case CHANNEL_NOTIFICATION_SOUND_VOLUME: setNotificationSoundVolume(((PercentType) command)); break; + case CHANNEL_FAVORITES_PLAY: + squeezeBoxServerHandler.playFavorite(mac, command.toString()); + break; default: break; } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 5da70161d5b1f..758dc059d04be 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -8,7 +8,7 @@ */ package org.openhab.binding.squeezebox.handler; -import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.SQUEEZEBOXSERVER_THING_TYPE; +import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.*; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; +import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; @@ -40,7 +41,10 @@ import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.State; +import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxServerConfig; +import org.openhab.binding.squeezebox.internal.model.Favorite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,8 +81,10 @@ public class SqueezeBoxServerHandler extends BaseBridgeHandler { private List squeezeBoxPlayerListeners = Collections .synchronizedList(new ArrayList()); + private Map players = Collections .synchronizedMap(new HashMap()); + // client socket and listener thread private Socket clientSocket; private SqueezeServerListener listener; @@ -100,7 +106,7 @@ public SqueezeBoxServerHandler(Bridge bridge) { @Override public void initialize() { - logger.debug("initializing server handler for thing {}", getThing()); + logger.debug("initializing server handler for thing {}", getThing().getUID()); scheduler.schedule(new Runnable() { @@ -113,7 +119,7 @@ public void run() { @Override public void dispose() { - logger.debug("disposing server handler for thing {}", getThing()); + logger.debug("disposing server handler for thing {}", getThing().getUID()); cancelReconnect(); disconnect(); } @@ -257,6 +263,10 @@ public void showStrings(String mac, String line1, String line2, int duration) { sendCommand(mac + " show line1:" + line1 + " line2:" + line2 + " duration:" + String.valueOf(duration)); } + public void playFavorite(String mac, String favorite) { + sendCommand(mac + " favorites playlist play item_id:" + favorite); + } + /** * Send a generic command to a given player * @@ -274,6 +284,13 @@ public void requestPlayers() { sendCommand("players 0"); } + /** + * Ask for favorites list + */ + public void requestFavorites() { + sendCommand("favorites items 0 100"); + } + /** * Login to server */ @@ -370,6 +387,15 @@ private void disconnect() { logger.trace("Squeeze Server connection stopped."); } + private void updateChannel(String channelID, State state) { + logger.trace("Updating channel {} for {} to state {}", channelID, getThing().getUID(), state); + try { + updateState(channelID, state); + } catch (IllegalStateException e) { + logger.error("Could not update channel on thing {}", getThing().getUID(), e); + } + } + private class SqueezeServerListener extends Thread { private boolean terminate = false; @@ -392,6 +418,7 @@ public void run() { login(); updateStatus(ThingStatus.ONLINE); requestPlayers(); + requestFavorites(); sendCommand("listen 1"); String message = null; @@ -405,6 +432,8 @@ public void run() { if (message.startsWith("players 0")) { handlePlayersList(message); + } else if (message.startsWith("favorites")) { + handleFavorites(message); } else { handlePlayerUpdate(message); } @@ -574,7 +603,6 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } else { listener.absoluteVolumeChangeEvent(mac, volume); } - } catch (NumberFormatException e) { logger.warn("Unable to parse volume [{}] received from mixer message.", volumeStringValue, e); @@ -847,6 +875,114 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } } } + + private void handleFavorites(String message) { + logger.trace("Handle favorites message: {}", message); + + String[] messageParts = message.split("\\s"); + if (messageParts.length == 2 && "changed".equals(messageParts[1])) { + // LMS informing us that favorites have changed; request an update to the favorites list + requestFavorites(); + return; + } + if (messageParts.length < 7) { + logger.trace("No favorites in message."); + return; + } + + List favorites = new ArrayList(); + String title = ""; + String count = ""; + Favorite f = null; + for (String part : messageParts) { + String id; + String name; + String type; + Boolean isaudio; + Boolean hasitems; + + // Title of Favorites + if (part.startsWith("title%3A")) { + title = decode(part.substring("title%3A".length())); + logger.trace("Favorite title: {}", title); + } + // Number of favorites in this message + else if (part.startsWith("count%3A")) { + count = part.substring("count%3A".length()); + logger.trace("Favorite count: {}", count); + } + // Favorite ID (in form xxxxxxxxx.n) + else if (part.startsWith("id%3A")) { + id = part.substring("id%3A".length()); + f = new Favorite(id); + favorites.add(f); + } + // Favorite name + else if (part.startsWith("name%3A")) { + name = decode(part.substring("name%3A".length())); + if (f != null) { + f.name = name; + } + } + // Favorite type + else if (part.startsWith("type%3A")) { + type = decode(part.substring("type%3A".length())); + if (f != null) { + f.type = type; + } + } + // Favorite is audio + else if (part.startsWith("isaudio%3A")) { + isaudio = new Boolean("1".matches(part.substring("isaudio%3A".length()))); + if (f != null) { + f.isaudio = isaudio; + } + } + // When "1", favorite is a submenu with additional favorites + else if (part.startsWith("hasitems%3A")) { + hasitems = new Boolean("1".matches(part.substring("hasitems%3A".length()))); + if (f != null) { + f.hasitems = hasitems; + } + } + } + updateChannelFavoritesList(favorites); + } + + private void updateChannelFavoritesList(List favorites) { + // Get config parameter indicating whether name should be wrapped with double quotes + final boolean includeQuotes = getConfigAs(SqueezeBoxServerConfig.class).quoteFavoritesList; + final String quote = includeQuotes ? "\"" : ""; + String adjustedName; + + StringBuilder sb = new StringBuilder(); + for (Favorite favorite : favorites) { + if (favorite.hasitems) { + // Skip favorites that are folders with sub-items as we + // only want favorites at the root level + continue; + } + sb.append(favorite.shortId + "="); + // If not quoting, we don't want any embedded commas + adjustedName = includeQuotes ? favorite.name : favorite.name.replaceAll(",", ""); + sb.append(quote + adjustedName + quote); + sb.append(","); + } + + // If the channel doesn't exist we can't update it + if (getThing().getChannel(CHANNEL_FAVORITES_LIST) == null) { + logger.debug("Channel '{}' does not exist. Delete and readd player thing to pick up channel.", + CHANNEL_FAVORITES_LIST); + return; + } + if (sb.length() == 0) { + updateChannel(CHANNEL_FAVORITES_LIST, UnDefType.NULL); + } else { + // Drop the last comma + sb.setLength(sb.length() - 1); + updateChannel(CHANNEL_FAVORITES_LIST, new StringType(sb.toString())); + } + } } /** diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java index e3b64bd46a476..55440899e52e5 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java @@ -40,4 +40,8 @@ public class SqueezeBoxServerConfig { * User ID (when authentication enabled in LMS) */ public String password; + /* + * When true, wrap the name of the favorite in quotes + */ + public boolean quoteFavoritesList; } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java new file mode 100644 index 0000000000000..4bac63226ea2d --- /dev/null +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2018 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.squeezebox.internal.model; + +/** + * Attributes of a Squeezebox Server favorite + * + * @author Mark Hilbush + * + */ +public class Favorite { + // id is of form xxxxxxxx.nn + public String id; + + // just the nn part of the id + public String shortId; + + // name of the favorite + public String name; + + // type of favorite (currently unused) + public String type; + + // indicates if favorite is audio (currently unused) + public Boolean isaudio; + + // indicates if favorite has sub-items + public Boolean hasitems; + + // URL of the favorite (currently unused) + public String url; + + public Favorite(String id) { + this.id = id; + this.shortId = id; + if (id.indexOf(".") != -1) { + this.shortId = id.substring(id.indexOf(".") + 1); + } + } + + @Override + public String toString() { + return "Favorite {id=" + id + ", shortId=" + shortId + ", name=" + name + ", type=" + type + ", isaudio=" + + isaudio + ", hasitems=" + hasitems + ", url=" + url + "}"; + } +} From 528681869356341d83314c426187c2714f3a9459 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Tue, 30 Jan 2018 06:45:21 -0500 Subject: [PATCH 02/14] Remove subfolders earlier in processing Signed-off-by: Mark Hilbush --- .../handler/SqueezeBoxServerHandler.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 758dc059d04be..4a03634ce65fa 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -942,7 +942,13 @@ else if (part.startsWith("isaudio%3A")) { else if (part.startsWith("hasitems%3A")) { hasitems = new Boolean("1".matches(part.substring("hasitems%3A".length()))); if (f != null) { - f.hasitems = hasitems; + if (hasitems) { + // Skip subfolders + favorites.remove(f); + f = null; + } else { + f.hasitems = hasitems; + } } } } @@ -957,14 +963,9 @@ private void updateChannelFavoritesList(List favorites) { StringBuilder sb = new StringBuilder(); for (Favorite favorite : favorites) { - if (favorite.hasitems) { - // Skip favorites that are folders with sub-items as we - // only want favorites at the root level - continue; - } - sb.append(favorite.shortId + "="); // If not quoting, we don't want any embedded commas adjustedName = includeQuotes ? favorite.name : favorite.name.replaceAll(",", ""); + sb.append(favorite.shortId + "="); sb.append(quote + adjustedName + quote); sb.append(","); } From 23724ad1a16e5753353674af333a1ca46cfc0578 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Tue, 30 Jan 2018 08:03:31 -0500 Subject: [PATCH 03/14] Pass favorites list to players Signed-off-by: Mark Hilbush --- .../SqueezeBoxNotificationListener.java | 6 ++++++ .../SqueezeBoxPlayerEventListener.java | 10 +++++++-- .../handler/SqueezeBoxPlayerHandler.java | 8 +++++++ .../handler/SqueezeBoxServerHandler.java | 21 ++++++++++++++++++- .../SqueezeBoxPlayerDiscoveryParticipant.java | 6 ++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java index afafdc05ad305..6937c5bf3daff 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java @@ -8,9 +8,11 @@ */ package org.openhab.binding.squeezebox.handler; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import org.openhab.binding.squeezebox.internal.model.Favorite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -201,4 +203,8 @@ public void remoteTitleChangeEvent(String mac, String title) { @Override public void irCodeChangeEvent(String mac, String ircode) { } + + @Override + public void updateFavoritesList(List favorites) { + } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java index d6c00bbcdc1aa..eeea3b9c0627c 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java @@ -8,6 +8,10 @@ */ package org.openhab.binding.squeezebox.handler; +import java.util.List; + +import org.openhab.binding.squeezebox.internal.model.Favorite; + /** * @author Markus Wolters * @author Ben Jones @@ -24,7 +28,7 @@ public interface SqueezeBoxPlayerEventListener { /** * Reports a new absolute volume for a given player. - * + * * @param mac * @param volume */ @@ -32,7 +36,7 @@ public interface SqueezeBoxPlayerEventListener { /** * Reports a relative volume change for a given player. - * + * * @param mac * @param volumeChange */ @@ -67,4 +71,6 @@ public interface SqueezeBoxPlayerEventListener { void remoteTitleChangeEvent(String mac, String title); void irCodeChangeEvent(String mac, String ircode); + + void updateFavoritesList(List favorites); } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 3eb8473bcd20b..3e261513a2196 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledFuture; @@ -43,6 +44,7 @@ import org.eclipse.smarthome.io.net.http.HttpUtil; import org.openhab.binding.squeezebox.SqueezeBoxBindingConstants; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxPlayerConfig; +import org.openhab.binding.squeezebox.internal.model.Favorite; import org.openhab.binding.squeezebox.internal.utils.SqueezeBoxTimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -456,6 +458,12 @@ public void irCodeChangeEvent(String mac, String ircode) { } } + @Override + public void updateFavoritesList(List favorites) { + // TODO: Process updated favorites list + logger.trace("Player {} Options: {}", mac, favorites); + } + /** * Update a channel if the mac matches our own * diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 4a03634ce65fa..17e24d69e2324 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -638,6 +638,7 @@ else if (messagePart.startsWith("mixer%20volume%3A")) { String value = messagePart.substring("mixer%20volume%3A".length()); final int volume = (int) Double.parseDouble(value); updatePlayer(new PlayerUpdateEvent() { + @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.absoluteVolumeChangeEvent(mac, volume); @@ -646,7 +647,9 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } // Parameter Mode else if (messagePart.startsWith("mode%3A")) { + final String mode = messagePart.substring("mode%3A".length()); + updatePlayer(new PlayerUpdateEvent() { @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { @@ -655,7 +658,9 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { }); } // Parameter Playing Time - else if (messagePart.startsWith("time%3A")) { + else if (messagePart.startsWith("time%3A")) + + { String value = messagePart.substring("time%3A".length()); final int time = (int) Double.parseDouble(value); updatePlayer(new PlayerUpdateEvent() { @@ -839,10 +844,12 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } final String value = mode; updatePlayer(new PlayerUpdateEvent() { + @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.modeChangeEvent(mac, value); } + }); } @@ -867,10 +874,12 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } else if (function.equals("volume")) { final int volume = (int) Double.parseDouble(value); updatePlayer(new PlayerUpdateEvent() { + @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.absoluteVolumeChangeEvent(mac, volume); } + }); } } @@ -952,9 +961,19 @@ else if (part.startsWith("hasitems%3A")) { } } } + updatePlayersFavoritesList(favorites); updateChannelFavoritesList(favorites); } + private void updatePlayersFavoritesList(List favorites) { + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.updateFavoritesList(favorites); + } + }); + } + private void updateChannelFavoritesList(List favorites) { // Get config parameter indicating whether name should be wrapped with double quotes final boolean includeQuotes = getConfigAs(SqueezeBoxServerConfig.class).quoteFavoritesList; diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java index 84838d5f807c6..b73cdae973707 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java @@ -11,6 +11,7 @@ import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.SQUEEZEBOXPLAYER_THING_TYPE; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -23,6 +24,7 @@ import org.openhab.binding.squeezebox.handler.SqueezeBoxPlayerEventListener; import org.openhab.binding.squeezebox.handler.SqueezeBoxPlayerHandler; import org.openhab.binding.squeezebox.handler.SqueezeBoxServerHandler; +import org.openhab.binding.squeezebox.internal.model.Favorite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -194,4 +196,8 @@ public void remoteTitleChangeEvent(String mac, String title) { @Override public void irCodeChangeEvent(String mac, String ircode) { } + + @Override + public void updateFavoritesList(List favorites) { + } } From 2f9aafbd2617964d8aad1a681e222f62852fd652 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Tue, 30 Jan 2018 12:18:24 -0500 Subject: [PATCH 04/14] Update state options when favorites updated Signed-off-by: Mark Hilbush --- .../META-INF/MANIFEST.MF | 83 ++++++++++--------- .../handler/SqueezeBoxPlayerHandler.java | 18 +++- .../internal/SqueezeBoxHandlerFactory.java | 14 +++- .../StateDescriptionOptionsProvider.java | 59 +++++++++++++ 4 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java diff --git a/addons/binding/org.openhab.binding.squeezebox/META-INF/MANIFEST.MF b/addons/binding/org.openhab.binding.squeezebox/META-INF/MANIFEST.MF index e59fcceed8df8..62d6edaac514c 100644 --- a/addons/binding/org.openhab.binding.squeezebox/META-INF/MANIFEST.MF +++ b/addons/binding/org.openhab.binding.squeezebox/META-INF/MANIFEST.MF @@ -1,41 +1,42 @@ -Manifest-Version: 1.0 -Bundle-ClassPath: . -Bundle-ManifestVersion: 2 -Bundle-Name: SqueezeBox Binding -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Bundle-SymbolicName: org.openhab.binding.squeezebox;singleton:=true -Bundle-Vendor: openHAB -Bundle-Version: 2.3.0.qualifier -Export-Package: - org.openhab.binding.squeezebox, - org.openhab.binding.squeezebox.handler -Import-Package: - com.google.gson, - org.apache.commons.lang, - org.eclipse.jdt.annotation;resolution:=optional, - org.eclipse.jetty.client, - org.eclipse.jetty.client.api, - org.eclipse.jetty.client.util, - org.eclipse.jetty.http, - org.eclipse.jetty.util.component, - org.eclipse.smarthome.config.core, - org.eclipse.smarthome.config.discovery, - org.eclipse.smarthome.core.audio, - org.eclipse.smarthome.core.audio.utils, - org.eclipse.smarthome.core.cache, - org.eclipse.smarthome.core.library.types, - org.eclipse.smarthome.core.net, - org.eclipse.smarthome.core.thing, - org.eclipse.smarthome.core.thing.binding, - org.eclipse.smarthome.core.types, - org.eclipse.smarthome.io.net.http, - org.eclipse.smarthome.io.transport.upnp, - org.jupnp, - org.jupnp.model, - org.jupnp.model.meta, - org.jupnp.model.types, - org.openhab.binding.squeezebox, - org.openhab.binding.squeezebox.handler, - org.osgi.framework, - org.slf4j -Service-Component: OSGI-INF/*.xml +Manifest-Version: 1.0 +Bundle-ClassPath: . +Bundle-ManifestVersion: 2 +Bundle-Name: SqueezeBox Binding +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-SymbolicName: org.openhab.binding.squeezebox;singleton:=true +Bundle-Vendor: openHAB +Bundle-Version: 2.3.0.qualifier +Export-Package: + org.openhab.binding.squeezebox, + org.openhab.binding.squeezebox.handler +Import-Package: + com.google.gson, + org.apache.commons.lang, + org.eclipse.jdt.annotation;resolution:=optional, + org.eclipse.jetty.client, + org.eclipse.jetty.client.api, + org.eclipse.jetty.client.util, + org.eclipse.jetty.http, + org.eclipse.jetty.util.component, + org.eclipse.smarthome.config.core, + org.eclipse.smarthome.config.discovery, + org.eclipse.smarthome.core.audio, + org.eclipse.smarthome.core.audio.utils, + org.eclipse.smarthome.core.cache, + org.eclipse.smarthome.core.library.types, + org.eclipse.smarthome.core.net, + org.eclipse.smarthome.core.thing, + org.eclipse.smarthome.core.thing.binding, + org.eclipse.smarthome.core.thing.type, + org.eclipse.smarthome.core.types, + org.eclipse.smarthome.io.net.http, + org.eclipse.smarthome.io.transport.upnp, + org.jupnp, + org.jupnp.model, + org.jupnp.model.meta, + org.jupnp.model.types, + org.openhab.binding.squeezebox, + org.openhab.binding.squeezebox.handler, + org.osgi.framework, + org.slf4j +Service-Component: OSGI-INF/*.xml diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 3e261513a2196..635a9f55ca778 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -10,6 +10,7 @@ import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.*; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -40,9 +41,11 @@ import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.RefreshType; import org.eclipse.smarthome.core.types.State; +import org.eclipse.smarthome.core.types.StateOption; import org.eclipse.smarthome.core.types.UnDefType; import org.eclipse.smarthome.io.net.http.HttpUtil; import org.openhab.binding.squeezebox.SqueezeBoxBindingConstants; +import org.openhab.binding.squeezebox.internal.StateDescriptionOptionsProvider; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxPlayerConfig; import org.openhab.binding.squeezebox.internal.model.Favorite; import org.openhab.binding.squeezebox.internal.utils.SqueezeBoxTimeoutException; @@ -111,6 +114,8 @@ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements Squeeze private String callbackUrl; + private StateDescriptionOptionsProvider stateDescriptionProvider; + private static final ExpiringCacheMap IMAGE_CACHE = new ExpiringCacheMap<>( TimeUnit.MINUTES.toMillis(15)); // 15min @@ -118,10 +123,13 @@ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements Squeeze * Creates SqueezeBox Player Handler * * @param thing + * @param stateDescriptionProvider */ - public SqueezeBoxPlayerHandler(@NonNull Thing thing, String callbackUrl) { + public SqueezeBoxPlayerHandler(@NonNull Thing thing, String callbackUrl, + StateDescriptionOptionsProvider stateDescriptionProvider) { super(thing); this.callbackUrl = callbackUrl; + this.stateDescriptionProvider = stateDescriptionProvider; } @Override @@ -462,6 +470,14 @@ public void irCodeChangeEvent(String mac, String ircode) { public void updateFavoritesList(List favorites) { // TODO: Process updated favorites list logger.trace("Player {} Options: {}", mac, favorites); + + List options = new ArrayList<>(); + + for (Favorite favorite : favorites) { + options.add(new StateOption(favorite.shortId, favorite.name)); + } + stateDescriptionProvider.setStateOptions( + new ChannelUID(getThing().getUID(), SqueezeBoxBindingConstants.CHANNEL_FAVORITES_PLAY), options); } /** diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java index 12de37fbd76b9..c318db7252108 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java @@ -65,6 +65,8 @@ public class SqueezeBoxHandlerFactory extends BaseThingHandlerFactory { private Map> audioSinkRegistrations = new ConcurrentHashMap<>(); + private StateDescriptionOptionsProvider stateDescriptionProvider; + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); @@ -83,7 +85,8 @@ protected ThingHandler createHandler(Thing thing) { if (thingTypeUID.equals(SQUEEZEBOXPLAYER_THING_TYPE)) { logger.trace("creating handler for player thing {}", thing); - SqueezeBoxPlayerHandler playerHandler = new SqueezeBoxPlayerHandler(thing, createCallbackUrl()); + SqueezeBoxPlayerHandler playerHandler = new SqueezeBoxPlayerHandler(thing, createCallbackUrl(), + stateDescriptionProvider); // Register the player as an audio sink logger.trace("Registering an audio sink for player thing {}", thing.getUID()); @@ -198,4 +201,13 @@ protected void setNetworkAddressService(NetworkAddressService networkAddressServ protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) { this.networkAddressService = null; } + + @Reference + protected void setDynamicStateDescriptionProvider(StateDescriptionOptionsProvider provider) { + this.stateDescriptionProvider = provider; + } + + protected void unsetDynamicStateDescriptionProvider(StateDescriptionOptionsProvider provider) { + this.stateDescriptionProvider = null; + } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java new file mode 100644 index 0000000000000..f8611577b1615 --- /dev/null +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2010-2018 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.squeezebox.internal; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.thing.Channel; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.type.DynamicStateDescriptionProvider; +import org.eclipse.smarthome.core.types.StateDescription; +import org.eclipse.smarthome.core.types.StateOption; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; + +/** + * Dynamic provider of state options while leaving other state description fields as original. + * + * @author Gregory Moyer - Initial contribution + */ +@Component(service = { DynamicStateDescriptionProvider.class, StateDescriptionOptionsProvider.class }, immediate = true) +public class StateDescriptionOptionsProvider implements DynamicStateDescriptionProvider { + private final Map> channelOptionsMap = new ConcurrentHashMap<>(); + + public void setStateOptions(ChannelUID channelUID, List options) { + channelOptionsMap.put(channelUID, options); + } + + @Override + public @Nullable StateDescription getStateDescription(@NonNull Channel channel, @Nullable StateDescription original, + @Nullable Locale locale) { + List options = channelOptionsMap.get(channel.getUID()); + if (options == null) { + return null; + } + + if (original != null) { + return new StateDescription(original.getMinimum(), original.getMaximum(), original.getStep(), + original.getPattern(), original.isReadOnly(), options); + } + + return new StateDescription(null, null, null, null, false, options); + } + + @Deactivate + public void deactivate() { + channelOptionsMap.clear(); + } +} \ No newline at end of file From ccd4e176cbc0c8d0555e86cc5ca4c50ac02d46d1 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Wed, 31 Jan 2018 08:44:31 -0500 Subject: [PATCH 05/14] Cleanup Signed-off-by: Mark Hilbush --- .../org.openhab.binding.squeezebox/README.md | 10 ++++++++++ .../handler/SqueezeBoxNotificationListener.java | 3 ++- .../handler/SqueezeBoxPlayerEventListener.java | 3 ++- .../handler/SqueezeBoxPlayerHandler.java | 15 +++++++-------- .../handler/SqueezeBoxServerHandler.java | 5 ++--- .../internal/SqueezeBoxHandlerFactory.java | 6 +++--- ...queezeBoxStateDescriptionOptionsProvider.java} | 6 ++++-- .../SqueezeBoxPlayerDiscoveryParticipant.java | 3 ++- 8 files changed, 32 insertions(+), 19 deletions(-) rename addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/{StateDescriptionOptionsProvider.java => SqueezeBoxStateDescriptionOptionsProvider.java} (87%) diff --git a/addons/binding/org.openhab.binding.squeezebox/README.md b/addons/binding/org.openhab.binding.squeezebox/README.md index 1f5a04ba5b98a..a1c0f6c92f4c7 100644 --- a/addons/binding/org.openhab.binding.squeezebox/README.md +++ b/addons/binding/org.openhab.binding.squeezebox/README.md @@ -91,6 +91,14 @@ All devices support some of the following channels: | notificationSoundVolume | Dimmer | Volume for playing notifications | | favoritesPlay | String | ID of Favorite to play (as available in server's favoritesList channel) | +## Playing Favorites + +Using the **favoritesPlay** channel, you can play a favorite from the *Favorites* list on the Logitech Media Server (LMS). +The favorites from the LMS will be populated into the state options of the **favoritesPlay** channel. +The Selection widget in HABpanel can be used to present the favorites as a choice list. +Selecting from that choice list will play the favorite on the SqueezeBox player. +Currently, only favorites from the root level of the LMS favorites list are exposed on the **favoritesPlay** channel. + ## Notifications ### How To Set Up @@ -146,3 +154,5 @@ end - There are some versions of squeezelite that will not correctly play very short duration mp3 files. Versions of squeezelite after v1.7 and before v1.8.6 will not play very short duration mp3 files reliably. For example, if you're using piCorePlayer (which uses squeezelite), please check your version of squeezelite if you're having trouble playing notifications. This bug has been fixed in squeezelite version 1.8.6-985, which is included in piCorePlayer version 3.20. - When streaming from a remote service (such as Pandora or Spotify), after the notification plays, the Squeezebox Server starts playing a new track, instead of picking up from where it left off on the currently playing track. + +- There have been reports that notifications do not play reliably, or do not play at all, when using Logitech Media Server (LMS) version 7.7.5. Therefore, it is recommended that the LMS be on a more current version than 7.7.5. diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java index 6937c5bf3daff..e805df069540b 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxNotificationListener.java @@ -21,6 +21,7 @@ * that's used to monitor certain events related to the notification functionality. * * @author Mark Hilbush - Implement AudioSink and notifications + * @author Mark Hilbush - Added event to update favorites list */ public final class SqueezeBoxNotificationListener implements SqueezeBoxPlayerEventListener { private Logger logger = LoggerFactory.getLogger(SqueezeBoxNotificationListener.class); @@ -205,6 +206,6 @@ public void irCodeChangeEvent(String mac, String ircode) { } @Override - public void updateFavoritesList(List favorites) { + public void updateFavoritesListEvent(List favorites) { } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java index eeea3b9c0627c..07aafe292c6ab 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerEventListener.java @@ -17,6 +17,7 @@ * @author Ben Jones * @author Dan Cunningham (OH2 Port) * @author Mark Hilbush added durationEvent + * @author Mark Hilbush - Added event to update favorites list */ public interface SqueezeBoxPlayerEventListener { @@ -72,5 +73,5 @@ public interface SqueezeBoxPlayerEventListener { void irCodeChangeEvent(String mac, String ircode); - void updateFavoritesList(List favorites); + void updateFavoritesListEvent(List favorites); } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 635a9f55ca778..a5fe163cd0e24 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -45,7 +45,7 @@ import org.eclipse.smarthome.core.types.UnDefType; import org.eclipse.smarthome.io.net.http.HttpUtil; import org.openhab.binding.squeezebox.SqueezeBoxBindingConstants; -import org.openhab.binding.squeezebox.internal.StateDescriptionOptionsProvider; +import org.openhab.binding.squeezebox.internal.SqueezeBoxStateDescriptionOptionsProvider; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxPlayerConfig; import org.openhab.binding.squeezebox.internal.model.Favorite; import org.openhab.binding.squeezebox.internal.utils.SqueezeBoxTimeoutException; @@ -61,6 +61,7 @@ * @author Mark Hilbush - Implement AudioSink and notifications * @author Mark Hilbush - Added duration channel * @author Patrik Gfeller - Timeout for TTS messages increased from 30 to 90s. + * @author Mark Hilbush - Get favorites from server and play favorite */ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements SqueezeBoxPlayerEventListener { @@ -114,7 +115,7 @@ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements Squeeze private String callbackUrl; - private StateDescriptionOptionsProvider stateDescriptionProvider; + private SqueezeBoxStateDescriptionOptionsProvider stateDescriptionProvider; private static final ExpiringCacheMap IMAGE_CACHE = new ExpiringCacheMap<>( TimeUnit.MINUTES.toMillis(15)); // 15min @@ -126,7 +127,7 @@ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements Squeeze * @param stateDescriptionProvider */ public SqueezeBoxPlayerHandler(@NonNull Thing thing, String callbackUrl, - StateDescriptionOptionsProvider stateDescriptionProvider) { + SqueezeBoxStateDescriptionOptionsProvider stateDescriptionProvider) { super(thing); this.callbackUrl = callbackUrl; this.stateDescriptionProvider = stateDescriptionProvider; @@ -137,6 +138,7 @@ public void initialize() { mac = getConfig().as(SqueezeBoxPlayerConfig.class).mac; timeCounter(); updateBridgeStatus(); + logger.debug("player thing {} initialized.", getThing().getUID()); } @Override @@ -467,12 +469,9 @@ public void irCodeChangeEvent(String mac, String ircode) { } @Override - public void updateFavoritesList(List favorites) { - // TODO: Process updated favorites list - logger.trace("Player {} Options: {}", mac, favorites); - + public void updateFavoritesListEvent(List favorites) { + logger.debug("Player {} updating favorites list", mac); List options = new ArrayList<>(); - for (Favorite favorite : favorites) { options.add(new StateOption(favorite.shortId, favorite.name)); } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 17e24d69e2324..5d112b8cea671 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -61,6 +61,7 @@ * @author Mark Hilbush - Added login/password authentication for LMS * @author Philippe Siem - Improve refresh of cover art url,remote title, artist, album, genre, year. * @author Patrik Gfeller - Support for mixer volume message added + * @author Mark Hilbush - Get favorites from LMS; update channel and send to players */ public class SqueezeBoxServerHandler extends BaseBridgeHandler { private Logger logger = LoggerFactory.getLogger(SqueezeBoxServerHandler.class); @@ -530,14 +531,12 @@ private void handlePlayersList(String message) { // Save player if we haven't seen it yet if (!players.containsKey(macAddress)) { players.put(macAddress, player); - updatePlayer(new PlayerUpdateEvent() { @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.playerAdded(player); } }); - // tell the server we want to subscribe to player updates sendCommand(player.getMacAddress() + " status - 1 subscribe:10 tags:yagJlNKjc"); } @@ -969,7 +968,7 @@ private void updatePlayersFavoritesList(List favorites) { updatePlayer(new PlayerUpdateEvent() { @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { - listener.updateFavoritesList(favorites); + listener.updateFavoritesListEvent(favorites); } }); } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java index c318db7252108..535222ac1e003 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java @@ -65,7 +65,7 @@ public class SqueezeBoxHandlerFactory extends BaseThingHandlerFactory { private Map> audioSinkRegistrations = new ConcurrentHashMap<>(); - private StateDescriptionOptionsProvider stateDescriptionProvider; + private SqueezeBoxStateDescriptionOptionsProvider stateDescriptionProvider; @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -203,11 +203,11 @@ protected void unsetNetworkAddressService(NetworkAddressService networkAddressSe } @Reference - protected void setDynamicStateDescriptionProvider(StateDescriptionOptionsProvider provider) { + protected void setDynamicStateDescriptionProvider(SqueezeBoxStateDescriptionOptionsProvider provider) { this.stateDescriptionProvider = provider; } - protected void unsetDynamicStateDescriptionProvider(StateDescriptionOptionsProvider provider) { + protected void unsetDynamicStateDescriptionProvider(SqueezeBoxStateDescriptionOptionsProvider provider) { this.stateDescriptionProvider = null; } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java similarity index 87% rename from addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java rename to addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java index f8611577b1615..211fd12813056 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/StateDescriptionOptionsProvider.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java @@ -27,9 +27,11 @@ * Dynamic provider of state options while leaving other state description fields as original. * * @author Gregory Moyer - Initial contribution + * @author Mark Hilbush - Adapted to squeezebox binding */ -@Component(service = { DynamicStateDescriptionProvider.class, StateDescriptionOptionsProvider.class }, immediate = true) -public class StateDescriptionOptionsProvider implements DynamicStateDescriptionProvider { +@Component(service = { DynamicStateDescriptionProvider.class, + SqueezeBoxStateDescriptionOptionsProvider.class }, immediate = true) +public class SqueezeBoxStateDescriptionOptionsProvider implements DynamicStateDescriptionProvider { private final Map> channelOptionsMap = new ConcurrentHashMap<>(); public void setStateOptions(ChannelUID channelUID, List options) { diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java index b73cdae973707..a5d54d6dffb08 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java @@ -35,6 +35,7 @@ * @author Dan Cunningham * @author Mark Hilbush - added method to cancel request player job, and to set thing properties * @author Mark Hilbush - Added duration channel + * @author Mark Hilbush - Added event to update favorites list * */ public class SqueezeBoxPlayerDiscoveryParticipant extends AbstractDiscoveryService @@ -198,6 +199,6 @@ public void irCodeChangeEvent(String mac, String ircode) { } @Override - public void updateFavoritesList(List favorites) { + public void updateFavoritesListEvent(List favorites) { } } From ccefd3911fc6af54136ffafff1dbfb0b19eb8514 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Wed, 31 Jan 2018 08:53:04 -0500 Subject: [PATCH 06/14] Fix formatting Signed-off-by: Mark Hilbush --- .../squeezebox/handler/SqueezeBoxServerHandler.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 5d112b8cea671..e343d0b36ed71 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -637,7 +637,6 @@ else if (messagePart.startsWith("mixer%20volume%3A")) { String value = messagePart.substring("mixer%20volume%3A".length()); final int volume = (int) Double.parseDouble(value); updatePlayer(new PlayerUpdateEvent() { - @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.absoluteVolumeChangeEvent(mac, volume); @@ -646,9 +645,7 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } // Parameter Mode else if (messagePart.startsWith("mode%3A")) { - final String mode = messagePart.substring("mode%3A".length()); - updatePlayer(new PlayerUpdateEvent() { @Override public void updateListener(SqueezeBoxPlayerEventListener listener) { @@ -657,9 +654,7 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { }); } // Parameter Playing Time - else if (messagePart.startsWith("time%3A")) - - { + else if (messagePart.startsWith("time%3A")) { String value = messagePart.substring("time%3A".length()); final int time = (int) Double.parseDouble(value); updatePlayer(new PlayerUpdateEvent() { @@ -733,7 +728,6 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { listener.titleChangeEvent(mac, decode(value)); } }); - } // Parameter Remote Title (radio) else if (messagePart.startsWith("remote_title%3A")) { From 1b7d64a101391d0c72209276ef45ae4cb193535e Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Thu, 1 Feb 2018 15:59:15 -0500 Subject: [PATCH 07/14] Incorporate review feedback. Signed-off-by: Mark Hilbush --- .../ESH-INF/thing/thing-types.xml | 4 +- .../SqueezeBoxBindingConstants.java | 2 +- .../handler/SqueezeBoxPlayerHandler.java | 3 +- .../handler/SqueezeBoxServerHandler.java | 9 ++-- ...ezeBoxStateDescriptionOptionsProvider.java | 2 +- .../squeezebox/internal/model/Favorite.java | 42 ++++++++++++++----- 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml index fac7535570614..cb7be365fe10d 100644 --- a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml +++ b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml @@ -84,7 +84,7 @@ - + @@ -110,7 +110,7 @@ Comma-separated list of favorites of form favoriteId=favoriteName - + String Play favorite by sending command with favoriteId diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java index fe11c6b32a2a7..80e918e4206b7 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/SqueezeBoxBindingConstants.java @@ -60,5 +60,5 @@ public class SqueezeBoxBindingConstants { public static final String CHANNEL_NAME = "name"; public static final String CHANNEL_MODEL = "model"; public static final String CHANNEL_NOTIFICATION_SOUND_VOLUME = "notificationSoundVolume"; - public static final String CHANNEL_FAVORITES_PLAY = "favoritesPlay"; + public static final String CHANNEL_FAVORITES_PLAY = "playFavorite"; } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index a5fe163cd0e24..d57361c5c3c21 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -475,8 +475,7 @@ public void updateFavoritesListEvent(List favorites) { for (Favorite favorite : favorites) { options.add(new StateOption(favorite.shortId, favorite.name)); } - stateDescriptionProvider.setStateOptions( - new ChannelUID(getThing().getUID(), SqueezeBoxBindingConstants.CHANNEL_FAVORITES_PLAY), options); + stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FAVORITES_PLAY), options); } /** diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index e343d0b36ed71..9282c77cc24ba 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -307,7 +307,6 @@ public void login() { * Send a command to the Squeeze Server. */ private synchronized void sendCommand(String command) { - if (getThing().getStatus() != ThingStatus.ONLINE) { return; } @@ -892,7 +891,7 @@ private void handleFavorites(String message) { return; } - List favorites = new ArrayList(); + List favorites = new ArrayList<>(); String title = ""; String count = ""; Favorite f = null; @@ -977,14 +976,12 @@ private void updateChannelFavoritesList(List favorites) { for (Favorite favorite : favorites) { // If not quoting, we don't want any embedded commas adjustedName = includeQuotes ? favorite.name : favorite.name.replaceAll(",", ""); - sb.append(favorite.shortId + "="); - sb.append(quote + adjustedName + quote); - sb.append(","); + sb.append(favorite.shortId).append("=").append(quote).append(adjustedName).append(quote).append(","); } // If the channel doesn't exist we can't update it if (getThing().getChannel(CHANNEL_FAVORITES_LIST) == null) { - logger.debug("Channel '{}' does not exist. Delete and readd player thing to pick up channel.", + logger.debug("Channel '{}' does not exist. Delete and readd player thing to pick up channel.", CHANNEL_FAVORITES_LIST); return; } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java index 211fd12813056..2db7146a576f9 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java @@ -58,4 +58,4 @@ public void setStateOptions(ChannelUID channelUID, List options) { public void deactivate() { channelOptionsMap.clear(); } -} \ No newline at end of file +} diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java index 4bac63226ea2d..686213d94e8f1 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java @@ -11,31 +11,50 @@ /** * Attributes of a Squeezebox Server favorite * - * @author Mark Hilbush + * @author Mark Hilbush - Initial contribution * */ public class Favorite { - // id is of form xxxxxxxx.nn + /** + * Favorite id is of form xxxxxxxx.nn + */ public String id; - // just the nn part of the id + /** + * Just the nn part of the id + */ public String shortId; - // name of the favorite + /** + * The name given to the favorite in the Squeezebox Server. + */ public String name; - // type of favorite (currently unused) + /** + * Type of favorite (currently unused) + */ public String type; - // indicates if favorite is audio (currently unused) + /** + * Indicates if the favorite is audio (currently unused) + */ public Boolean isaudio; - // indicates if favorite has sub-items + /** + * Indicates if favorite has sub-items + */ public Boolean hasitems; - // URL of the favorite (currently unused) + /** + * URL of the favorite (currently unused) + */ public String url; + /** + * Creates a preset from the given favorite id + * + * @param id Squeezebox Server internal identifier for favorite + */ public Favorite(String id) { this.id = id; this.shortId = id; @@ -46,7 +65,10 @@ public Favorite(String id) { @Override public String toString() { - return "Favorite {id=" + id + ", shortId=" + shortId + ", name=" + name + ", type=" + type + ", isaudio=" - + isaudio + ", hasitems=" + hasitems + ", url=" + url + "}"; + StringBuilder sb = new StringBuilder(); + sb.append("Favorite {id=").append(id).append(", shortId=").append(shortId).append(", name=").append(name) + .append(", type=").append(type).append(", isaudio=").append(isaudio).append(", hasitems=") + .append(hasitems).append(", url=").append(url).append("}"); + return sb.toString(); } } From f889f3dbea44339ca550523d6d6f74a2e6cd113c Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Thu, 1 Feb 2018 16:10:47 -0500 Subject: [PATCH 08/14] Add newline Signed-off-by: Mark Hilbush --- .../internal/SqueezeBoxStateDescriptionOptionsProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java index 2db7146a576f9..a1dd9ddac3860 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java @@ -50,7 +50,6 @@ public void setStateOptions(ChannelUID channelUID, List options) { return new StateDescription(original.getMinimum(), original.getMaximum(), original.getStep(), original.getPattern(), original.isReadOnly(), options); } - return new StateDescription(null, null, null, null, false, options); } From 8bc3d576985ffa5fd78aa21adbe4bde0de9f2519 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Fri, 2 Feb 2018 06:23:48 -0500 Subject: [PATCH 09/14] Remove unneeded import Signed-off-by: Mark Hilbush --- .../binding/squeezebox/handler/SqueezeBoxPlayerHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index d57361c5c3c21..72a9f7acf3373 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -44,7 +44,6 @@ import org.eclipse.smarthome.core.types.StateOption; import org.eclipse.smarthome.core.types.UnDefType; import org.eclipse.smarthome.io.net.http.HttpUtil; -import org.openhab.binding.squeezebox.SqueezeBoxBindingConstants; import org.openhab.binding.squeezebox.internal.SqueezeBoxStateDescriptionOptionsProvider; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxPlayerConfig; import org.openhab.binding.squeezebox.internal.model.Favorite; @@ -640,8 +639,7 @@ public PercentType getNotificationSoundVolume() { logger.debug("Initializing notification volume to current player volume"); notificationSoundVolume = currentVolume(); if (notificationSoundVolume != 0) { - updateState(SqueezeBoxBindingConstants.CHANNEL_NOTIFICATION_SOUND_VOLUME, - new PercentType(notificationSoundVolume)); + updateState(CHANNEL_NOTIFICATION_SOUND_VOLUME, new PercentType(notificationSoundVolume)); } } return PercentType.valueOf(String.valueOf(notificationSoundVolume)); From 07aa61726ccf44083e9992b6b638ddbeafac0c13 Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Fri, 2 Feb 2018 06:30:59 -0500 Subject: [PATCH 10/14] Fix documentation Signed-off-by: Mark Hilbush --- addons/binding/org.openhab.binding.squeezebox/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/README.md b/addons/binding/org.openhab.binding.squeezebox/README.md index a1c0f6c92f4c7..008808dcf9ed8 100644 --- a/addons/binding/org.openhab.binding.squeezebox/README.md +++ b/addons/binding/org.openhab.binding.squeezebox/README.md @@ -89,15 +89,15 @@ All devices support some of the following channels: | ircode | String | Received IR code | | numberPlaylistTracks | Number | Number of playlist tracks | | notificationSoundVolume | Dimmer | Volume for playing notifications | -| favoritesPlay | String | ID of Favorite to play (as available in server's favoritesList channel) | +| playFavorite | String | ID of Favorite to play (channel's state options contains available favorites) | ## Playing Favorites -Using the **favoritesPlay** channel, you can play a favorite from the *Favorites* list on the Logitech Media Server (LMS). -The favorites from the LMS will be populated into the state options of the **favoritesPlay** channel. +Using the **playFavorite** channel, you can play a favorite from the *Favorites* list on the Logitech Media Server (LMS). +The favorites from the LMS will be populated into the state options of the **playFavorite** channel. The Selection widget in HABpanel can be used to present the favorites as a choice list. Selecting from that choice list will play the favorite on the SqueezeBox player. -Currently, only favorites from the root level of the LMS favorites list are exposed on the **favoritesPlay** channel. +Currently, only favorites from the root level of the LMS favorites list are exposed on the **playFavorite** channel. ## Notifications From 290a8e37b8a54a6df7954749a6a84505ccc911aa Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Fri, 2 Feb 2018 14:02:58 -0500 Subject: [PATCH 11/14] Move config parameter from thing to channel. Signed-off-by: Mark Hilbush --- .../ESH-INF/thing/thing-types.xml | 12 ++++---- .../handler/SqueezeBoxServerHandler.java | 30 +++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml index cb7be365fe10d..831d9128e919d 100644 --- a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml +++ b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml @@ -41,11 +41,6 @@ Password used to login to Squeeze Server password - - - Wrap the right hand side of the favorites in quotes - false - @@ -109,6 +104,13 @@ Comma-separated list of favorites of form favoriteId=favoriteName + + + + Wrap the right hand side of the favorites in quotes + false + + String diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 9282c77cc24ba..fd4dad859a5ab 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -33,6 +33,7 @@ import org.apache.commons.lang.StringUtils; import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatus; @@ -80,6 +81,8 @@ public class SqueezeBoxServerHandler extends BaseBridgeHandler { private static final int VOLUME_CHANGE_SIZE = 5; private static final String NEW_LINE = System.getProperty("line.separator"); + private static final String CHANNEL_CONFIG_QUOTE_FAVORITES_LIST = "quoteFavoritesList"; + private List squeezeBoxPlayerListeners = Collections .synchronizedList(new ArrayList()); @@ -967,24 +970,25 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } private void updateChannelFavoritesList(List favorites) { - // Get config parameter indicating whether name should be wrapped with double quotes - final boolean includeQuotes = getConfigAs(SqueezeBoxServerConfig.class).quoteFavoritesList; - final String quote = includeQuotes ? "\"" : ""; - String adjustedName; + final Channel channel = thing.getChannel(CHANNEL_FAVORITES_LIST); + if (channel == null) { + logger.debug("Channel {} doesn't exist. Delete & add thing to get channel.", CHANNEL_FAVORITES_LIST); + return; + } + // Get channel config parameter indicating whether name should be wrapped with double quotes + Boolean includeQuotes = Boolean.FALSE; + if (channel.getConfiguration().containsKey(CHANNEL_CONFIG_QUOTE_FAVORITES_LIST)) { + includeQuotes = (Boolean) channel.getConfiguration().get(CHANNEL_CONFIG_QUOTE_FAVORITES_LIST); + } + + final String quote = includeQuotes.booleanValue() ? "\"" : ""; StringBuilder sb = new StringBuilder(); for (Favorite favorite : favorites) { - // If not quoting, we don't want any embedded commas - adjustedName = includeQuotes ? favorite.name : favorite.name.replaceAll(",", ""); - sb.append(favorite.shortId).append("=").append(quote).append(adjustedName).append(quote).append(","); + sb.append(favorite.shortId).append("=").append(quote).append(favorite.name.replaceAll(",", "")) + .append(quote).append(","); } - // If the channel doesn't exist we can't update it - if (getThing().getChannel(CHANNEL_FAVORITES_LIST) == null) { - logger.debug("Channel '{}' does not exist. Delete and readd player thing to pick up channel.", - CHANNEL_FAVORITES_LIST); - return; - } if (sb.length() == 0) { updateChannel(CHANNEL_FAVORITES_LIST, UnDefType.NULL); } else { From 6dd820e8575468d9583c605f5b0dc5ff8d1ca7ee Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Sat, 3 Feb 2018 06:27:33 -0500 Subject: [PATCH 12/14] Incorporate review feedback Signed-off-by: Mark Hilbush --- .../ESH-INF/thing/thing-types.xml | 2 +- addons/binding/org.openhab.binding.squeezebox/README.md | 2 +- .../squeezebox/handler/SqueezeBoxServerHandler.java | 8 ++++---- .../internal/config/SqueezeBoxServerConfig.java | 4 ---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml index 831d9128e919d..4f4802c89c8cb 100644 --- a/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml +++ b/addons/binding/org.openhab.binding.squeezebox/ESH-INF/thing/thing-types.xml @@ -105,7 +105,7 @@ Comma-separated list of favorites of form favoriteId=favoriteName - + Wrap the right hand side of the favorites in quotes false diff --git a/addons/binding/org.openhab.binding.squeezebox/README.md b/addons/binding/org.openhab.binding.squeezebox/README.md index 008808dcf9ed8..f40a8e10c2644 100644 --- a/addons/binding/org.openhab.binding.squeezebox/README.md +++ b/addons/binding/org.openhab.binding.squeezebox/README.md @@ -48,7 +48,7 @@ Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport= Or, if Squeeze Server authentication is enabled: ``` -Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport=9000, cliport=9090, userId="yourid", password="yourpassword", quoteFavoritesList=true ] +Bridge squeezebox:squeezeboxserver:myServer [ ipAddress="192.168.1.10", webport=9000, cliport=9090, userId="yourid", password="yourpassword" ] { Thing squeezeboxplayer myplayer[ mac="00:f1:bb:00:00:f1" ] } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index fd4dad859a5ab..86ecc45ecdcd7 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -81,7 +81,7 @@ public class SqueezeBoxServerHandler extends BaseBridgeHandler { private static final int VOLUME_CHANGE_SIZE = 5; private static final String NEW_LINE = System.getProperty("line.separator"); - private static final String CHANNEL_CONFIG_QUOTE_FAVORITES_LIST = "quoteFavoritesList"; + private static final String CHANNEL_CONFIG_QUOTE_LIST = "quoteList"; private List squeezeBoxPlayerListeners = Collections .synchronizedList(new ArrayList()); @@ -970,7 +970,7 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } private void updateChannelFavoritesList(List favorites) { - final Channel channel = thing.getChannel(CHANNEL_FAVORITES_LIST); + final Channel channel = getThing().getChannel(CHANNEL_FAVORITES_LIST); if (channel == null) { logger.debug("Channel {} doesn't exist. Delete & add thing to get channel.", CHANNEL_FAVORITES_LIST); return; @@ -978,8 +978,8 @@ private void updateChannelFavoritesList(List favorites) { // Get channel config parameter indicating whether name should be wrapped with double quotes Boolean includeQuotes = Boolean.FALSE; - if (channel.getConfiguration().containsKey(CHANNEL_CONFIG_QUOTE_FAVORITES_LIST)) { - includeQuotes = (Boolean) channel.getConfiguration().get(CHANNEL_CONFIG_QUOTE_FAVORITES_LIST); + if (channel.getConfiguration().containsKey(CHANNEL_CONFIG_QUOTE_LIST)) { + includeQuotes = (Boolean) channel.getConfiguration().get(CHANNEL_CONFIG_QUOTE_LIST); } final String quote = includeQuotes.booleanValue() ? "\"" : ""; diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java index 55440899e52e5..e3b64bd46a476 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/config/SqueezeBoxServerConfig.java @@ -40,8 +40,4 @@ public class SqueezeBoxServerConfig { * User ID (when authentication enabled in LMS) */ public String password; - /* - * When true, wrap the name of the favorite in quotes - */ - public boolean quoteFavoritesList; } From 70ecca669da0160cc51b3864c3ab4469d28d445d Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Mon, 5 Feb 2018 17:02:43 -0500 Subject: [PATCH 13/14] Incorporate review feedback Signed-off-by: Mark Hilbush --- .../handler/SqueezeBoxServerHandler.java | 44 +++---------------- .../squeezebox/internal/model/Favorite.java | 23 +--------- 2 files changed, 6 insertions(+), 61 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 86ecc45ecdcd7..fd6624b3e8d40 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -895,63 +895,29 @@ private void handleFavorites(String message) { } List favorites = new ArrayList<>(); - String title = ""; - String count = ""; Favorite f = null; for (String part : messageParts) { - String id; - String name; - String type; - Boolean isaudio; - Boolean hasitems; - - // Title of Favorites - if (part.startsWith("title%3A")) { - title = decode(part.substring("title%3A".length())); - logger.trace("Favorite title: {}", title); - } - // Number of favorites in this message - else if (part.startsWith("count%3A")) { - count = part.substring("count%3A".length()); - logger.trace("Favorite count: {}", count); - } // Favorite ID (in form xxxxxxxxx.n) - else if (part.startsWith("id%3A")) { - id = part.substring("id%3A".length()); + if (part.startsWith("id%3A")) { + String id = part.substring("id%3A".length()); f = new Favorite(id); favorites.add(f); } // Favorite name else if (part.startsWith("name%3A")) { - name = decode(part.substring("name%3A".length())); + String name = decode(part.substring("name%3A".length())); if (f != null) { f.name = name; } } - // Favorite type - else if (part.startsWith("type%3A")) { - type = decode(part.substring("type%3A".length())); - if (f != null) { - f.type = type; - } - } - // Favorite is audio - else if (part.startsWith("isaudio%3A")) { - isaudio = new Boolean("1".matches(part.substring("isaudio%3A".length()))); - if (f != null) { - f.isaudio = isaudio; - } - } // When "1", favorite is a submenu with additional favorites else if (part.startsWith("hasitems%3A")) { - hasitems = new Boolean("1".matches(part.substring("hasitems%3A".length()))); + boolean hasitems = "1".matches(part.substring("hasitems%3A".length())); if (f != null) { if (hasitems) { // Skip subfolders favorites.remove(f); f = null; - } else { - f.hasitems = hasitems; } } } @@ -982,7 +948,7 @@ private void updateChannelFavoritesList(List favorites) { includeQuotes = (Boolean) channel.getConfiguration().get(CHANNEL_CONFIG_QUOTE_LIST); } - final String quote = includeQuotes.booleanValue() ? "\"" : ""; + String quote = includeQuotes.booleanValue() ? "\"" : ""; StringBuilder sb = new StringBuilder(); for (Favorite favorite : favorites) { sb.append(favorite.shortId).append("=").append(quote).append(favorite.name.replaceAll(",", "")) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java index 686213d94e8f1..c6fa24e427638 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/model/Favorite.java @@ -30,26 +30,6 @@ public class Favorite { */ public String name; - /** - * Type of favorite (currently unused) - */ - public String type; - - /** - * Indicates if the favorite is audio (currently unused) - */ - public Boolean isaudio; - - /** - * Indicates if favorite has sub-items - */ - public Boolean hasitems; - - /** - * URL of the favorite (currently unused) - */ - public String url; - /** * Creates a preset from the given favorite id * @@ -67,8 +47,7 @@ public Favorite(String id) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Favorite {id=").append(id).append(", shortId=").append(shortId).append(", name=").append(name) - .append(", type=").append(type).append(", isaudio=").append(isaudio).append(", hasitems=") - .append(hasitems).append(", url=").append(url).append("}"); + .append("}"); return sb.toString(); } } From a03e904e219dbb24e90efd077aa67b088765686a Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Tue, 6 Feb 2018 07:49:04 -0500 Subject: [PATCH 14/14] Additional rework from review Signed-off-by: Mark Hilbush --- .../handler/SqueezeBoxPlayerHandler.java | 6 +----- .../handler/SqueezeBoxServerHandler.java | 16 ++++------------ ...queezeBoxStateDescriptionOptionsProvider.java | 5 +++-- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 72a9f7acf3373..5e107a4c80588 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -490,11 +490,7 @@ private void updateChannel(String mac, String channelID, State state) { if (prevState == null || !prevState.equals(state)) { logger.trace("Updating channel {} for thing {} with mac {} to state {}", channelID, getThing().getUID(), mac, state); - try { - updateState(channelID, state); - } catch (Exception e) { - logger.error("Could not update channel", e); - } + updateState(channelID, state); } } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index fd6624b3e8d40..08bf0a0396867 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -42,7 +42,6 @@ import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.State; import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.squeezebox.internal.config.SqueezeBoxServerConfig; import org.openhab.binding.squeezebox.internal.model.Favorite; @@ -390,15 +389,6 @@ private void disconnect() { logger.trace("Squeeze Server connection stopped."); } - private void updateChannel(String channelID, State state) { - logger.trace("Updating channel {} for {} to state {}", channelID, getThing().getUID(), state); - try { - updateState(channelID, state); - } catch (IllegalStateException e) { - logger.error("Could not update channel on thing {}", getThing().getUID(), e); - } - } - private class SqueezeServerListener extends Thread { private boolean terminate = false; @@ -956,11 +946,13 @@ private void updateChannelFavoritesList(List favorites) { } if (sb.length() == 0) { - updateChannel(CHANNEL_FAVORITES_LIST, UnDefType.NULL); + updateState(CHANNEL_FAVORITES_LIST, UnDefType.NULL); } else { // Drop the last comma sb.setLength(sb.length() - 1); - updateChannel(CHANNEL_FAVORITES_LIST, new StringType(sb.toString())); + String favoritesList = sb.toString(); + logger.trace("Updating favorites channel for {} to state {}", getThing().getUID(), favoritesList); + updateState(CHANNEL_FAVORITES_LIST, new StringType(favoritesList)); } } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java index a1dd9ddac3860..12358ea3aa600 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxStateDescriptionOptionsProvider.java @@ -13,7 +13,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; @@ -31,6 +31,7 @@ */ @Component(service = { DynamicStateDescriptionProvider.class, SqueezeBoxStateDescriptionOptionsProvider.class }, immediate = true) +@NonNullByDefault public class SqueezeBoxStateDescriptionOptionsProvider implements DynamicStateDescriptionProvider { private final Map> channelOptionsMap = new ConcurrentHashMap<>(); @@ -39,7 +40,7 @@ public void setStateOptions(ChannelUID channelUID, List options) { } @Override - public @Nullable StateDescription getStateDescription(@NonNull Channel channel, @Nullable StateDescription original, + public @Nullable StateDescription getStateDescription(Channel channel, @Nullable StateDescription original, @Nullable Locale locale) { List options = channelOptionsMap.get(channel.getUID()); if (options == null) {