Fix warnings (#19453)

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen
2025-10-11 13:26:36 +02:00
committed by GitHub
parent 231f216f57
commit f346fa2236
25 changed files with 221 additions and 186 deletions
@@ -23,7 +23,6 @@ import org.openhab.binding.heos.internal.handler.HeosThingBaseHandler;
import org.openhab.binding.heos.internal.resources.Telnet.ReadException;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioHTTPServer;
import org.openhab.core.audio.AudioSink;
import org.openhab.core.audio.AudioSinkAsync;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.audio.FileAudioStream;
@@ -38,7 +37,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This makes HEOS to serve as an {@link AudioSink}.
* This makes HEOS to serve as an {@link org.openhab.core.audio.AudioSink}.
*
* @author Johannes Einig - Initial contribution
* @author Laurent Garnier - Extend AudioSinkAsync
@@ -29,7 +29,6 @@ import org.openhab.binding.heos.internal.json.payload.Group;
import org.openhab.binding.heos.internal.json.payload.Media;
import org.openhab.binding.heos.internal.json.payload.Player;
import org.openhab.binding.heos.internal.resources.HeosCommands;
import org.openhab.binding.heos.internal.resources.HeosConstants;
import org.openhab.binding.heos.internal.resources.HeosEventListener;
import org.openhab.binding.heos.internal.resources.Telnet.ReadException;
import org.slf4j.Logger;
@@ -84,13 +83,14 @@ public class HeosFacade {
List<Media> media = new ArrayList<>();
for (int page = 0; page < MAX_QUEUE_PAGES; page++) {
HeosResponseObject<Media[]> response = fetchQueue(pid, page);
if (!response.result || response.payload == null) {
Media[] payload = response.payload;
if (!response.result || payload == null) {
break;
}
media.addAll(Arrays.asList(response.payload));
media.addAll(Arrays.asList(payload));
if (response.payload.length < 100) {
if (payload.length < 100) {
break;
}
@@ -457,8 +457,10 @@ public class HeosFacade {
/**
* Asks for the actual state of the player. The result has
* to be handled by the event controller. The system returns {@link HeosConstants#PLAY},
* {@link HeosConstants#PAUSE} or {@link HeosConstants#STOP}.
* to be handled by the event controller. The system returns
* {@link org.openhab.binding.heos.internal.resources.HeosConstants#PLAY},
* {@link org.openhab.binding.heos.internal.resources.HeosConstants#PAUSE} or
* {@link org.openhab.binding.heos.internal.resources.HeosConstants#STOP}.
*
* @param id The player ID the state shall get for
* @return
@@ -144,7 +144,6 @@ public class HeosSystem {
eventSendCommand.stopInputListener(HeosCommands.registerChangeEventOff());
eventSendCommand.disconnect();
sendCommand.disconnect();
@Nullable
ExecutorService executor = this.singleThreadExecutor;
if (executor != null && executor.isShutdown()) {
executor.shutdownNow();
@@ -13,7 +13,6 @@
package org.openhab.binding.heos.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Configuration wrapper for bridge configuration
@@ -32,12 +31,12 @@ public class BridgeConfiguration {
/**
* Username for login to the HEOS account.
*/
public @Nullable String username;
public String username = "";
/**
* Password for login to the HEOS account
*/
public @Nullable String password;
public String password = "";
/**
* The time in seconds for the HEOS Heartbeat (default = 60 s)
@@ -18,6 +18,7 @@ import static org.openhab.binding.heos.internal.handler.FutureUtil.cancel;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -189,9 +190,10 @@ public class HeosPlayerDiscovery extends AbstractDiscoveryService implements Heo
private <K, V> Map<K, V> findRemovedEntries(Map<K, V> mapNew, Map<K, V> mapOld) {
Map<K, V> removedItems = new HashMap<>();
for (K key : mapOld.keySet()) {
for (Entry<K, V> entry : mapOld.entrySet()) {
K key = entry.getKey();
if (!mapNew.containsKey(key)) {
removedItems.put(key, mapOld.get(key));
removedItems.put(key, entry.getValue());
}
}
return removedItems;
@@ -13,13 +13,13 @@
package org.openhab.binding.heos.internal.discovery;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.heos.internal.handler.HeosBridgeHandler;
/**
* The {@link HeosPlayerDiscoveryListener } is an Event Listener
* for the HEOS network. Handler which wants the get informed
* if the player or groups within the HEOS network have changed has to
* implement this class and register itself at the {@link HeosBridgeHandler}
* implement this class and register itself at the
* {@link org.openhab.binding.heos.internal.handler.HeosBridgeHandler}
*
* @author Johannes Einig - Initial contribution
*/
@@ -24,6 +24,8 @@ import org.openhab.binding.heos.internal.json.dto.HeosErrorCode;
*/
@NonNullByDefault
public class HeosFunctionalException extends IOException {
private static final long serialVersionUID = 1L;
private final HeosErrorCode code;
public HeosFunctionalException(HeosErrorCode code) {
@@ -23,6 +23,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
*/
@NonNullByDefault
public class HeosNotConnectedException extends IOException {
private static final long serialVersionUID = 1L;
public HeosNotConnectedException() {
super("HEOS not connected");
}
@@ -23,6 +23,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
*/
@NonNullByDefault
public class HeosNotFoundException extends IOException {
private static final long serialVersionUID = 1L;
public HeosNotFoundException() {
super("HEOS not found");
}
@@ -83,10 +83,10 @@ import org.slf4j.LoggerFactory;
*/
@NonNullByDefault
public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventListener {
private final Logger logger = LoggerFactory.getLogger(HeosBridgeHandler.class);
private static final int HEOS_PORT = 1255;
private final Logger logger = LoggerFactory.getLogger(HeosBridgeHandler.class);
private final Set<HeosMediaEventListener> heosMediaEventListeners = new CopyOnWriteArraySet<>();
private final List<HeosPlayerDiscoveryListener> playerDiscoveryList = new CopyOnWriteArrayList<>();
private final HeosChannelManager channelManager = new HeosChannelManager(this);
@@ -121,16 +121,13 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
if (command instanceof RefreshType) {
return;
}
@Nullable
Channel channel = this.getThing().getChannel(channelUID.getId());
if (channel == null) {
logger.debug("No valid channel found");
return;
}
@Nullable
ChannelTypeUID channelTypeUID = channel.getChannelTypeUID();
@Nullable
HeosChannelHandler channelHandler = channelHandlerFactory.getChannelHandler(channelUID, this, channelTypeUID);
if (channelHandler != null) {
try {
@@ -157,7 +154,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
}
private void delayedInitialize() {
@Nullable
HeosFacade connection = null;
try {
logger.debug("Running scheduledStartUp job");
@@ -170,11 +166,9 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
// gets all available player and groups to ensure that the system knows
// about the conjunction between the groupMemberHash and the GID
triggerPlayerDiscovery();
@Nullable
String username = configuration.username;
@Nullable
String password = configuration.password;
if (username != null && !"".equals(username) && password != null && !"".equals(password)) {
if (!username.isBlank() && !password.isBlank()) {
login(connection, username, password);
} else {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_ERROR,
@@ -195,9 +189,7 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
private void fetchPlayersAndGroups() {
try {
@Nullable
Player[] onlinePlayers = getApiConnection().getPlayers().payload;
@Nullable
Group[] onlineGroups = getApiConnection().getGroups().payload;
if (onlinePlayers != null && onlineGroups != null) {
@@ -208,17 +200,13 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
}
}
private void updatePlayerStatus(@Nullable Player[] onlinePlayers, @Nullable Group[] onlineGroups) {
if (onlinePlayers == null || onlineGroups == null) {
return;
}
private void updatePlayerStatus(Player[] onlinePlayers, Group[] onlineGroups) {
Set<String> players = Stream.of(onlinePlayers).map(p -> Objects.toString(p.playerId))
.collect(Collectors.toSet());
Set<String> groups = Stream.of(onlineGroups).map(p -> p.id).collect(Collectors.toSet());
for (Thing thing : getThing().getThings()) {
try {
@Nullable
ThingHandler handler = thing.getHandler();
if (handler instanceof HeosThingBaseHandler heosHandler) {
Set<String> target = handler instanceof HeosPlayerHandler ? players : groups;
@@ -260,7 +248,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
return;
}
@Nullable
HeosError error = response.getError();
logger.debug("Failed to login: {}", error);
updateStatus(ONLINE, ThingStatusDetail.CONFIGURATION_ERROR,
@@ -276,7 +263,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
cancel(future);
}
@Nullable
HeosFacade localApiConnection = apiConnection;
if (localApiConnection == null) {
logger.debug("Not disposing bridge because of missing apiConnection");
@@ -296,9 +282,11 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
@Override
public synchronized void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
logger.debug("Disposing child handler for: {}.", childThing.getUID().getId());
if (bridgeHandlerDisposalOngoing) { // Checks if bridgeHandler is going to disposed (by stopping the binding or
if (bridgeHandlerDisposalOngoing) {
// Checks if bridgeHandler is going to disposed (by stopping the binding or
// openHAB for example) and prevents it from being updated which stops the
// disposal process.
return;
} else if (childHandler instanceof HeosPlayerHandler) {
String channelIdentifier = "P" + childThing.getUID().getId();
updateThingChannels(channelManager.removeSingleChannel(channelIdentifier));
@@ -326,7 +314,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
/**
* Sets the HEOS Thing offline
*/
@SuppressWarnings("null")
public void setGroupOffline(String groupMemberHash) {
HeosGroupHandler groupHandler = groupHandlerMap.get(groupMemberHash);
if (groupHandler != null) {
@@ -358,7 +345,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
try {
String channelIdentifier = "";
String pid = "";
@Nullable
ThingHandler handler = childThing.getHandler();
if (handler instanceof HeosPlayerHandler playerHandler) {
channelIdentifier = "P" + childThing.getUID().getId();
@@ -372,7 +358,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
}
}
Map<String, String> properties = new HashMap<>();
@Nullable
String playerName = childThing.getLabel();
playerName = playerName == null ? pid : playerName;
ChannelUID channelUID = new ChannelUID(getThing().getUID(), channelIdentifier);
@@ -444,7 +429,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
public Player[] getPlayers() throws IOException, ReadException {
HeosResponseObject<Player[]> response = getApiConnection().getPlayers();
@Nullable
Player[] players = response.payload;
if (players == null) {
throw new IOException("Received no valid payload");
@@ -454,7 +438,6 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
public Group[] getGroups() throws IOException, ReadException {
HeosResponseObject<Group[]> response = getApiConnection().getGroups();
@Nullable
Group[] groups = response.payload;
if (groups == null) {
throw new IOException("Received no valid payload");
@@ -502,13 +485,11 @@ public class HeosBridgeHandler extends BaseBridgeHandler implements HeosEventLis
}
public boolean isBridgeConnected() {
@Nullable
HeosFacade connection = apiConnection;
return connection != null && connection.isConnected();
}
public HeosFacade getApiConnection() throws HeosNotConnectedException {
@Nullable
HeosFacade localApiConnection = apiConnection;
if (localApiConnection != null) {
return localApiConnection;
@@ -65,7 +65,6 @@ public class HeosChannelHandlerInputs extends BaseHeosChannelHandler {
private void handleCommand(Command command, String id) throws IOException, ReadException {
if (command instanceof RefreshType) {
@Nullable
Media payload = getApi().getNowPlayingMedia(id).payload;
if (payload != null) {
eventListener.playerMediaChangeEvent(id, payload);
@@ -62,7 +62,6 @@ public class HeosChannelHandlerNowPlaying extends BaseHeosChannelHandler {
private void handleCommand(Command command, String id) throws IOException, ReadException {
if (command instanceof RefreshType) {
// TODO consider caching this somehow, this method is triggered from a lot of channels for the same player
@Nullable
Media payload = getApi().getNowPlayingMedia(id).payload;
if (payload != null) {
eventListener.playerMediaChangeEvent(id, payload);
@@ -13,7 +13,8 @@
package org.openhab.binding.heos.internal.handler;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -65,9 +66,9 @@ public class HeosChannelHandlerPlayURL extends BaseHeosChannelHandler {
return;
}
try {
URL url = new URL(command.toString());
URL url = new URI(command.toString()).toURL();
getApi().playURL(id, url);
} catch (MalformedURLException e) {
} catch (URISyntaxException e) {
logger.debug("Command '{}' is not a proper URL. Error: {}", command.toString(), e.getMessage());
}
}
@@ -39,11 +39,14 @@ import org.osgi.service.component.annotations.Component;
public class HeosDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
String getValueByLabel(ChannelUID channelUID, String input) {
Optional<String> optionalValueByLabel = channelOptionsMap.get(channelUID).stream()
.filter(o -> input.equals(o.getLabel())).map(StateOption::getValue).findFirst();
List<StateOption> options = channelOptionsMap.get(channelUID);
if (options == null) {
return input;
}
// if no match was found we assume that it already was a value and not a label
return Objects.requireNonNull(optionalValueByLabel.orElse(input));
return Objects.requireNonNull(options.stream().filter(o -> input.equals(o.getLabel()))
.map(StateOption::getValue).findFirst().orElse(input));
}
public void setFavorites(ChannelUID channelUID, List<BrowseResult> favorites) {
@@ -64,7 +67,6 @@ public class HeosDynamicStateDescriptionProvider extends BaseDynamicStateDescrip
private Optional<StateOption> getStateOption(Function<BrowseResult, @Nullable String> function,
BrowseResult browseResult) {
@Nullable
String identifier = function.apply(browseResult);
if (identifier != null) {
return Optional.of(new StateOption(identifier, browseResult.name));
@@ -72,11 +72,9 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
// Only commands from the UNGROUP channel are passed through
// to activate the group if it is offline
if (gid != null || CH_ID_UNGROUP.equals(channelUID.getId())) {
@Nullable
HeosChannelHandler channelHandler = getHeosChannelHandler(channelUID);
if (channelHandler != null) {
try {
@Nullable
String id = getMaybeId(channelUID, command);
channelHandler.handleGroupCommand(command, id, thing.getUID(), this);
handleSuccess();
@@ -87,8 +85,7 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
}
}
@Nullable
private String getMaybeId(ChannelUID channelUID, Command command) throws HeosNotFoundException {
private @Nullable String getMaybeId(ChannelUID channelUID, Command command) throws HeosNotFoundException {
if (isCreateGroupRequest(channelUID, command)) {
return null;
} else {
@@ -125,7 +122,6 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
@Override
public String getId() throws HeosNotFoundException {
@Nullable
String localGroupId = this.gid;
if (localGroupId == null) {
throw new HeosNotFoundException();
@@ -159,11 +155,8 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
return;
}
@Nullable
String localGid = this.gid;
@Nullable
String eventGroupId = eventObject.getAttribute(HeosCommunicationAttribute.GROUP_ID);
@Nullable
String eventPlayerId = eventObject.getAttribute(HeosCommunicationAttribute.PLAYER_ID);
if (localGid == null || !(localGid.equals(eventGroupId) || localGid.equals(eventPlayerId))) {
return;
@@ -185,7 +178,6 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
return;
}
@Nullable
String localGid = this.gid;
if (localGid == null || !localGid.equals(responseObject.getAttribute(HeosCommunicationAttribute.GROUP_ID))) {
return;
@@ -246,7 +238,6 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
}
private void delayedInitialize() {
@Nullable
HeosBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler == null) {
@@ -262,7 +253,6 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
bridgeHandler.addGroupHandlerInformation(this);
// Checks if there is a group online with the same group member hash.
// If not setting the group offline.
@Nullable
String groupId = bridgeHandler.getActualGID(HeosGroup.calculateGroupMemberHash(configuration.members));
if (groupId == null) {
blockInitialization = false;
@@ -272,7 +262,6 @@ public class HeosGroupHandler extends HeosThingBaseHandler {
refreshPlayState(groupId);
HeosResponseObject<Group> response = getApiConnection().getGroupInfo(groupId);
@Nullable
Group group = response.payload;
if (group == null) {
throw new IllegalStateException("Invalid group response received");
@@ -60,7 +60,6 @@ public class HeosPlayerHandler extends HeosThingBaseHandler {
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
@Nullable
HeosChannelHandler channelHandler = getHeosChannelHandler(channelUID);
if (channelHandler != null) {
try {
@@ -16,11 +16,12 @@ import static org.openhab.binding.heos.internal.HeosBindingConstants.*;
import static org.openhab.binding.heos.internal.handler.FutureUtil.cancel;
import static org.openhab.binding.heos.internal.json.dto.HeosCommandGroup.*;
import static org.openhab.binding.heos.internal.json.dto.HeosCommunicationAttribute.*;
import static org.openhab.binding.heos.internal.resources.HeosConstants.*;
import static org.openhab.core.thing.ThingStatus.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
@@ -100,9 +101,7 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
@Override
public void initialize() {
@Nullable
Bridge bridge = getBridge();
@Nullable
HeosBridgeHandler localBridgeHandler;
if (bridge != null) {
localBridgeHandler = (HeosBridgeHandler) bridge.getHandler();
@@ -147,7 +146,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
}
public HeosFacade getApiConnection() throws HeosNotConnectedException {
@Nullable
HeosBridgeHandler localBridge = bridgeHandler;
if (localBridge != null) {
return localBridge.getApiConnection();
@@ -171,7 +169,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
@Nullable
HeosChannelHandler getHeosChannelHandler(ChannelUID channelUID) {
@Nullable
HeosChannelHandlerFactory localChannelHandlerFactory = this.channelHandlerFactory;
return localChannelHandlerFactory != null ? localChannelHandlerFactory.getChannelHandler(channelUID, this, null)
: null;
@@ -251,9 +248,9 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
*/
public void playURL(String urlStr) throws IOException, ReadException {
try {
URL url = new URL(urlStr);
URL url = new URI(urlStr).toURL();
getApiConnection().playURL(getId(), url);
} catch (MalformedURLException e) {
} catch (URISyntaxException e) {
logger.debug("Command '{}' is not a proper URL. Error: {}", urlStr, e.getMessage());
}
}
@@ -269,7 +266,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
protected void handleThingStateUpdate(HeosEventObject eventObject) {
updateStatus(ONLINE, ThingStatusDetail.NONE, "Receiving events");
@Nullable
HeosEvent command = eventObject.command;
if (command == null) {
@@ -284,7 +280,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
case PLAYER_VOLUME_CHANGED:
case GROUP_VOLUME_CHANGED:
@Nullable
String level = eventObject.getAttribute(LEVEL);
if (level != null) {
notificationVolume = level;
@@ -298,9 +293,7 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
break;
case PLAYER_NOW_PLAYING_PROGRESS:
@Nullable
Long position = eventObject.getNumericAttribute(CURRENT_POSITION);
@Nullable
Long duration = eventObject.getNumericAttribute(DURATION);
if (position != null && duration != null) {
updateState(CH_ID_CUR_POS, quantityFromMilliSeconds(position));
@@ -352,7 +345,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
protected <T> void handleThingStateUpdate(HeosResponseObject<T> responseObject) throws HeosFunctionalException {
handleResponseError(responseObject);
@Nullable
HeosCommandTuple cmd = responseObject.heosCommand;
if (cmd == null) {
@@ -371,7 +363,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
break;
case GET_VOLUME:
@Nullable
String level = responseObject.getAttribute(LEVEL);
if (level != null) {
notificationVolume = level;
@@ -399,12 +390,15 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
handlePlayerInfo(player);
}
break;
default:
logger.trace("Unhandled command {} for command group {}", cmd.command, cmd.commandGroup);
break;
}
}
}
private <T> void handleResponseError(HeosResponseObject<T> responseObject) throws HeosFunctionalException {
@Nullable
HeosError error = responseObject.getError();
if (error != null) {
throw new HeosFunctionalException(error.code);
@@ -412,7 +406,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
}
private void handleRepeatMode(HeosObject eventObject) {
@Nullable
String repeatMode = eventObject.getAttribute(REPEAT);
if (repeatMode == null) {
updateState(CH_ID_REPEAT_MODE, UnDefType.NULL);
@@ -435,7 +428,6 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
}
private void playerStateChanged(HeosObject eventObject) {
@Nullable
String attribute = eventObject.getAttribute(STATE);
if (attribute == null) {
updateState(CH_ID_CONTROL, UnDefType.NULL);
@@ -491,13 +483,13 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
String imageUrl = info.imageUrl;
if (imageUrl != null && !imageUrl.isBlank()) {
try {
URL url = new URL(imageUrl); // checks if String is proper URL
URL url = new URI(imageUrl).toURL(); // checks if String is proper URL
RawType cover = HttpUtil.downloadImage(url.toString());
if (cover != null) {
updateState(CH_ID_COVER, cover);
return;
}
} catch (MalformedURLException e) {
} catch (URISyntaxException | MalformedURLException e) {
logger.debug("Cover can't be loaded. No proper URL: {}", imageUrl, e);
}
}
@@ -513,8 +505,9 @@ public abstract class HeosThingBaseHandler extends BaseThingHandler implements H
}
private void handleSourceId(Media info) {
if (info.sourceId == INPUT_SID && info.mediaId != null) {
String inputName = info.mediaId.substring(info.mediaId.indexOf("/") + 1);
String mediaId = info.mediaId;
if (info.sourceId == INPUT_SID && mediaId != null) {
String inputName = mediaId.substring(mediaId.indexOf("/") + 1);
updateState(CH_ID_INPUTS, StringType.valueOf(inputName));
updateState(CH_ID_TYPE, StringType.valueOf(info.station));
} else {
@@ -46,7 +46,7 @@ public class HeosJsonParser {
.create();
public HeosEventObject parseEvent(String jsonBody) {
HeosJsonWrapper wrapper = gson.fromJson(jsonBody, HeosJsonWrapper.class);
HeosJsonWrapper wrapper = Objects.requireNonNull(gson.fromJson(jsonBody, HeosJsonWrapper.class));
return postProcess(wrapper.heos);
}
@@ -61,6 +61,7 @@ public class HeosJsonParser {
}
private <T> HeosResponseObject<T> postProcess(HeosJsonWrapper wrapper, Class<T> clazz) {
@Nullable
T payload = gson.fromJson(wrapper.payload, clazz);
return new HeosResponseObject<>(HeosCommandTuple.valueOf(wrapper.heos.command), wrapper.heos.command,
@@ -41,7 +41,6 @@ public abstract class HeosObject {
}
public @Nullable Long getNumericAttribute(HeosCommunicationAttribute attributeName) {
@Nullable
String attribute = attributes.get(attributeName.getLabel());
if (attribute == null) {
@@ -13,16 +13,16 @@
package org.openhab.binding.heos.internal.resources;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.heos.internal.api.HeosEventController;
import org.openhab.binding.heos.internal.exception.HeosFunctionalException;
import org.openhab.binding.heos.internal.json.dto.HeosEventObject;
import org.openhab.binding.heos.internal.json.dto.HeosResponseObject;
/**
* The {@link HeosEventListener } is an Event Listener
* for the HEOS network. Handler which wants the get informed
* by an HEOS event via the {@link HeosEventController} has to
* implement this class and register itself at the {@link HeosEventController}
* The {@link HeosEventListener } is an Event Listener for the HEOS network.
* Handler which wants the get informed by an HEOS event via the
* {@link org.openhab.binding.heos.internal.api.HeosEventController}
* has to implement this class and register itself at the
* {@link org.openhab.binding.heos.internal.api.HeosEventController}
*
* @author Johannes Einig - Initial contribution
* @author Martin van Wingerden - change handling of stop/pause depending on playing item type
@@ -15,16 +15,16 @@ package org.openhab.binding.heos.internal.resources;
import java.util.EventListener;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.heos.internal.api.HeosEventController;
import org.openhab.binding.heos.internal.handler.HeosBridgeHandler;
import org.openhab.binding.heos.internal.json.payload.Media;
/**
* The {@link HeosMediaEventListener } is a dedicated Event Listener
* for the HEOS media events. Handler which wants the get informed
* by an HEOS media event via the {@link HeosEventController} has to
* implement this class and register itself either at the
* {@link HeosEventController} or at {@link HeosBridgeHandler}
* by an HEOS media event via the
* {@link org.openhab.binding.heos.internal.api.HeosEventController}
* has to implement this class and register itself either at the
* {@link org.openhab.binding.heos.internal.api.HeosEventController} or at
* {@link org.openhab.binding.heos.internal.handler.HeosBridgeHandler}
*
* @author Martin van Wingerden - Initial contribution
*/
@@ -14,6 +14,7 @@ package org.openhab.binding.heos.internal.resources;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.heos.internal.json.HeosJsonParser;
import org.openhab.binding.heos.internal.json.dto.HeosResponseObject;
import org.openhab.binding.heos.internal.resources.Telnet.ReadException;
@@ -26,6 +27,7 @@ import org.slf4j.LoggerFactory;
*
* @author Johannes Einig - Initial contribution
*/
@NonNullByDefault
public class HeosSendCommand {
private final Logger logger = LoggerFactory.getLogger(HeosSendCommand.class);
@@ -41,9 +43,7 @@ public class HeosSendCommand {
int attempt = 0;
boolean send = client.send(command);
if (clazz == null) {
return null;
} else if (send) {
if (send) {
String line = client.readLine();
if (line == null) {
throw new IOException("No valid input was received");
@@ -31,6 +31,7 @@ import java.util.concurrent.TimeoutException;
import org.apache.commons.net.io.CRLFLineReader;
import org.apache.commons.net.telnet.TelnetClient;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.NamedThreadFactory;
import org.slf4j.Logger;
@@ -42,6 +43,7 @@ import org.slf4j.LoggerFactory;
*
* @author Johannes Einig - Initial contribution
*/
@NonNullByDefault
public class Telnet {
private final Logger logger = LoggerFactory.getLogger(Telnet.class);
@@ -50,16 +52,16 @@ public class Telnet {
private final HeosStringPropertyChangeListener eolNotifier = new HeosStringPropertyChangeListener();
private final TelnetClient client = new TelnetClient();
private ExecutorService timedReaderExecutor;
private @Nullable ExecutorService timedReaderExecutor;
private String ip;
private @Nullable String ip;
private int port;
private String readResult = "";
private InetAddress address;
private DataOutputStream outStream;
private BufferedInputStream bufferedStream;
private @Nullable InetAddress address;
private @Nullable DataOutputStream outStream;
private @Nullable BufferedInputStream bufferedStream;
/**
* Connects to a host with the specified IP address and port
@@ -115,7 +117,8 @@ public class Telnet {
* @throws IOException
*/
private void sendClear(String command) throws IOException {
if (!client.isConnected()) {
DataOutputStream outStream = this.outStream;
if (!client.isConnected() || outStream == null) {
return;
}
@@ -134,7 +137,7 @@ public class Telnet {
* @throws IOException
* @see #readLine(int timeOut)
*/
public String readLine() throws ReadException, IOException {
public @Nullable String readLine() throws ReadException, IOException {
return readLine(READ_TIMEOUT);
}
@@ -168,8 +171,10 @@ public class Telnet {
Throwable cause = e.getCause();
if (cause instanceof IOException exception) {
throw exception;
} else {
} else if (cause != null) {
throw new ReadException(cause);
} else {
throw new ReadException(e);
}
}
}
@@ -178,6 +183,10 @@ public class Telnet {
private String timedCallable(Callable<String> callable, int timeOut)
throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService timedReaderExecutor = this.timedReaderExecutor;
if (timedReaderExecutor == null) {
throw new IllegalStateException("timedReaderExecutor is not initialized");
}
Future<String> future = timedReaderExecutor.submit(callable);
try {
return future.get(timeOut, TimeUnit.MILLISECONDS);
@@ -194,7 +203,10 @@ public class Telnet {
*/
public void disconnect() throws IOException {
client.disconnect();
timedReaderExecutor.shutdown();
ExecutorService timedReaderExecutor = this.timedReaderExecutor;
if (timedReaderExecutor != null) {
timedReaderExecutor.shutdown();
}
}
/**
@@ -216,6 +228,11 @@ public class Telnet {
* available data without any check
*/
private void inputAvailableRead() {
BufferedInputStream bufferedStream = this.bufferedStream;
if (bufferedStream == null) {
return;
}
try {
int i = bufferedStream.available();
byte[] buffer = new byte[i];
@@ -252,6 +269,7 @@ public class Telnet {
* @return true if HEOS is reachable
*/
public boolean isHostReachable() {
InetAddress address = this.address;
try {
return address != null && address.isReachable(IS_ALIVE_TIMEOUT);
} catch (IOException e) {
@@ -32,7 +32,7 @@ public class HeosJsonParserEventTest {
private final HeosJsonParser subject = new HeosJsonParser();
@Test
public void event_now_playing_changed() {
public void eventNowPlayingChanged() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/player_now_playing_changed\", \"message\": \"pid=1679855527\"}}");
@@ -42,7 +42,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_now_playing_progress() {
public void eventNowPlayingProgress() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/player_now_playing_progress\", \"message\": \"pid=1679855527&cur_pos=224848000&duration=0\"}}");
@@ -54,7 +54,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_state_changed() {
public void eventStateChanged() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/player_state_changed\", \"message\": \"pid=1679855527&state=play\"}}");
@@ -65,7 +65,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_playback_error() {
public void eventPlaybackError() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/player_playback_error\", \"message\": \"pid=1679855527&error=Could Not Download\"}}");
@@ -76,7 +76,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_volume_changed() {
public void eventVolumeChanged() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/player_volume_changed\", \"message\": \"pid=1958912779&level=23&mute=off\"}}");
@@ -88,7 +88,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_shuffle_mode_changed() {
public void eventShuffleModeChanged() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/shuffle_mode_changed\", \"message\": \"pid=-831584083&shuffle=on\"}}");
@@ -99,7 +99,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_sources_changed() {
public void eventSourcesChanged() {
HeosEventObject event = subject.parseEvent("{\"heos\": {\"command\": \"event/sources_changed\"}}");
assertEquals(HeosEvent.SOURCES_CHANGED, event.command);
@@ -107,7 +107,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_user_changed() {
public void eventUserChanged() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/user_changed\", \"message\": \"signed_in&un=martinvw@mtin.nl\"}}");
@@ -118,7 +118,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_unknown_event() {
public void eventUnknownEvent() {
HeosEventObject event = subject.parseEvent("{\"heos\": {\"command\": \"event/does_not_exist\"}}");
assertNull(event.command);
@@ -126,7 +126,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_duplicate_attributes() {
public void eventDuplicateAttributes() {
HeosEventObject event = subject.parseEvent(
"{\"heos\": {\"command\": \"event/does_not_exist\", \"message\": \"signed_in&un=test1&un=test2\"}}");
@@ -135,7 +135,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_non_numeric() {
public void eventNonNumeric() {
HeosEventObject event = subject
.parseEvent("{\"heos\": {\"command\": \"event/does_not_exist\", \"message\": \"pid=test\"}}");
@@ -144,7 +144,7 @@ public class HeosJsonParserEventTest {
}
@Test
public void event_numeric_missing() {
public void eventNumericMissing() {
HeosEventObject event = subject.parseEvent("{\"heos\": {\"command\": \"event/does_not_exist\"}}");
// the first one is ignored but it does not crash
@@ -21,6 +21,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.heos.internal.json.dto.HeosCommand;
import org.openhab.binding.heos.internal.json.dto.HeosCommandGroup;
import org.openhab.binding.heos.internal.json.dto.HeosCommandTuple;
import org.openhab.binding.heos.internal.json.dto.HeosError;
import org.openhab.binding.heos.internal.json.dto.HeosErrorCode;
import org.openhab.binding.heos.internal.json.dto.HeosResponseObject;
import org.openhab.binding.heos.internal.json.payload.BrowseResult;
@@ -42,13 +44,15 @@ public class HeosJsonParserResponseTest {
private final HeosJsonParser subject = new HeosJsonParser();
@Test
public void sign_in() {
public void signIn() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"system/sign_in\", \"result\": \"success\", \"message\": \"signed_in&un=test@example.org\"}}",
Void.class);
assertEquals(HeosCommandGroup.SYSTEM, response.heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.SYSTEM, heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, heosCommand.command);
assertTrue(response.result);
assertEquals("test@example.org", response.getAttribute(USERNAME));
@@ -56,38 +60,46 @@ public class HeosJsonParserResponseTest {
}
@Test
public void sign_in_under_process() {
public void signInUnderProcess() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"system/sign_in\", \"message\": \"command under process\"}}", Void.class);
assertEquals(HeosCommandGroup.SYSTEM, response.heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.SYSTEM, heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, heosCommand.command);
assertFalse(response.result);
assertFalse(response.isFinished());
}
@Test
public void sign_in_failed() {
public void signInFailed() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"system/sign_in\", \"message\": \"eid=10&text=User not found\"}}",
Void.class);
assertEquals(HeosCommandGroup.SYSTEM, response.heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.SYSTEM, heosCommand.commandGroup);
assertEquals(HeosCommand.SIGN_IN, heosCommand.command);
assertFalse(response.result);
assertTrue(response.isFinished());
assertEquals(HeosErrorCode.USER_NOT_FOUND, response.getError().code);
HeosError error = response.getError();
assertNotNull(error);
assertEquals(HeosErrorCode.USER_NOT_FOUND, error.code);
}
@Test
public void get_mute() {
public void getMute() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"player/get_mute\", \"result\": \"success\", \"message\": \"pid=1958912779&state=on\"}}",
Void.class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_MUTE, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_MUTE, heosCommand.command);
assertTrue(response.result);
assertEquals(Long.valueOf(1958912779), response.getNumericAttribute(PLAYER_ID));
@@ -95,26 +107,32 @@ public class HeosJsonParserResponseTest {
}
@Test
public void get_mute_error() {
public void getMuteError() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"player/get_mute\", \"result\": \"fail\", \"message\": \"eid=2&text=ID Not Valid&pid=null\"}}",
Void.class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_MUTE, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_MUTE, heosCommand.command);
assertFalse(response.result);
assertEquals(HeosErrorCode.INVALID_ID, response.getError().code);
HeosError error = response.getError();
assertNotNull(error);
assertEquals(HeosErrorCode.INVALID_ID, error.code);
}
@Test
public void browse_browse_under_process() {
public void browseBrowseUnderProcess() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"browse/browse\", \"result\": \"success\", \"message\": \"command under process&sid=1025\"}}",
Void.class);
assertEquals(HeosCommandGroup.BROWSE, response.heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.BROWSE, heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, heosCommand.command);
assertTrue(response.result);
assertEquals(Long.valueOf(1025), response.getNumericAttribute(SOURCE_ID));
@@ -122,21 +140,25 @@ public class HeosJsonParserResponseTest {
}
@Test
public void incorrect_level() {
public void incorrectLevel() {
HeosResponseObject<Void> response = subject.parseResponse(
"{\"heos\": {\"command\": \"player/set_volume\", \"result\": \"fail\", \"message\": \"eid=9&text=Parameter out of range&pid=-831584083&level=OFF\"}}",
Void.class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.SET_VOLUME, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.SET_VOLUME, heosCommand.command);
assertFalse(response.result);
assertEquals(HeosErrorCode.PARAMETER_OUT_OF_RANGE, response.getError().code);
assertEquals("#9: Parameter out of range", response.getError().code.toString());
HeosError error = response.getError();
assertNotNull(error);
assertEquals(HeosErrorCode.PARAMETER_OUT_OF_RANGE, error.code);
assertEquals("#9: Parameter out of range", error.code.toString());
}
@Test
public void get_players() {
public void getPlayers() {
HeosResponseObject<Player[]> response = subject.parseResponse(
"""
{"heos": {"command": "player/get_players", "result": "success", "message": ""}, "payload": [\
@@ -145,12 +167,17 @@ public class HeosJsonParserResponseTest {
""",
Player[].class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_PLAYERS, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_PLAYERS, heosCommand.command);
assertTrue(response.result);
assertEquals(2, response.payload.length);
Player player0 = response.payload[0];
Player[] payload = response.payload;
assertNotNull(payload);
assertEquals(2, payload.length);
Player player0 = payload[0];
assertEquals("Kantoor HEOS 3", player0.name);
assertEquals(-831584083, player0.playerId);
@@ -161,7 +188,7 @@ public class HeosJsonParserResponseTest {
assertEquals(0, player0.lineout);
assertEquals("ACNG9180110887", player0.serial);
Player player1 = response.payload[1];
Player player1 = payload[1];
assertEquals("HEOS Bar", player1.name);
assertEquals(1958912779, player1.playerId);
@@ -174,27 +201,31 @@ public class HeosJsonParserResponseTest {
}
@Test
public void get_player_info() {
public void getPlayerInfo() {
HeosResponseObject<Player> response = subject.parseResponse(
"{\"heos\": {\"command\": \"player/get_player_info\", \"result\": \"success\", \"message\": \"pid=1958912779\"}, \"payload\": {\"name\": \"HEOS Bar\", \"pid\": 1958912779, \"model\": \"HEOS Bar\", \"version\": \"1.520.200\", \"ip\": \"192.168.1.195\", \"network\": \"wired\", \"lineout\": 0, \"serial\": \"ADAG9180917029\"}}",
Player.class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_PLAYER_INFO, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_PLAYER_INFO, heosCommand.command);
assertTrue(response.result);
assertEquals("HEOS Bar", response.payload.name);
assertEquals(1958912779, response.payload.playerId);
assertEquals("HEOS Bar", response.payload.model);
assertEquals("1.520.200", response.payload.version);
assertEquals("192.168.1.195", response.payload.ip);
assertEquals("wired", response.payload.network);
assertEquals(0, response.payload.lineout);
assertEquals("ADAG9180917029", response.payload.serial);
Player payload = response.payload;
assertNotNull(payload);
assertEquals("HEOS Bar", payload.name);
assertEquals(1958912779, payload.playerId);
assertEquals("HEOS Bar", payload.model);
assertEquals("1.520.200", payload.version);
assertEquals("192.168.1.195", payload.ip);
assertEquals("wired", payload.network);
assertEquals(0, payload.lineout);
assertEquals("ADAG9180917029", payload.serial);
}
@Test
public void get_now_playing_media() {
public void getNowPlayingMedia() {
HeosResponseObject<Media> response = subject.parseResponse(
"""
{"heos": {"command": "player/get_now_playing_media", "result": "success", "message": "pid=1958912779"}, "payload": \
@@ -202,29 +233,33 @@ public class HeosJsonParserResponseTest {
""",
Media.class);
assertEquals(HeosCommandGroup.PLAYER, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_NOW_PLAYING_MEDIA, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.PLAYER, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_NOW_PLAYING_MEDIA, heosCommand.command);
assertTrue(response.result);
assertEquals(Long.valueOf(1958912779), response.getNumericAttribute(PLAYER_ID));
assertEquals("song", response.payload.type);
assertEquals("Solo (feat. Demi Lovato)", response.payload.song);
assertEquals("What Is Love? (Deluxe)", response.payload.album);
assertEquals("Clean Bandit", response.payload.artist);
Media payload = response.payload;
assertNotNull(payload);
assertEquals("song", payload.type);
assertEquals("Solo (feat. Demi Lovato)", payload.song);
assertEquals("What Is Love? (Deluxe)", payload.album);
assertEquals("Clean Bandit", payload.artist);
assertEquals(
"http://192.168.1.230:8015//m-browsableMediaUri/getImageFromTag/mnt/326C72A3E307501E47DE2B0F47D90EB8/Clean%20Bandit/What%20Is%20Love_%20(Deluxe)/03%20Solo%20(feat.%20Demi%20Lovato).m4a",
response.payload.imageUrl);
assertEquals("", response.payload.albumId);
payload.imageUrl);
assertEquals("", payload.albumId);
assertEquals(
"http://192.168.1.230:8015/m-1c176905-f6c7-d168-dc35-86b4735c5976/Clean+Bandit/What+Is+Love_+(Deluxe)/03+Solo+(feat.+Demi+Lovato).m4a",
response.payload.mediaId);
assertEquals(1, response.payload.queueId);
assertEquals(1024, response.payload.sourceId);
payload.mediaId);
assertEquals(1, payload.queueId);
assertEquals(1024, payload.sourceId);
}
@Test
public void browse_playlist() {
public void browsePlaylist() {
HeosResponseObject<BrowseResult[]> response = subject.parseResponse(
"""
{"heos": {"command": "browse/browse", "result": "success", "message": "sid=1025&returned=6&count=6"}, "payload": [\
@@ -237,15 +272,19 @@ public class HeosJsonParserResponseTest {
""",
BrowseResult[].class);
assertEquals(HeosCommandGroup.BROWSE, response.heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.BROWSE, heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, heosCommand.command);
assertTrue(response.result);
assertEquals(Long.valueOf(1025), response.getNumericAttribute(SOURCE_ID));
assertEquals(Long.valueOf(6), response.getNumericAttribute(RETURNED));
assertEquals(Long.valueOf(6), response.getNumericAttribute(COUNT));
BrowseResult result = response.payload[5];
BrowseResult[] payload = response.payload;
assertNotNull(payload);
BrowseResult result = payload[5];
assertEquals(YesNoEnum.YES, result.container);
assertEquals(BrowseResultType.PLAYLIST, result.type);
@@ -256,7 +295,7 @@ public class HeosJsonParserResponseTest {
}
@Test
public void browse_favorites() {
public void browseFavorites() {
HeosResponseObject<BrowseResult[]> response = subject.parseResponse(
"""
{"heos": {"command": "browse/browse", "result": "success", "message": "sid=1028&returned=3&count=3"}, "payload": [\
@@ -267,15 +306,19 @@ public class HeosJsonParserResponseTest {
""",
BrowseResult[].class);
assertEquals(HeosCommandGroup.BROWSE, response.heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.BROWSE, heosCommand.commandGroup);
assertEquals(HeosCommand.BROWSE, heosCommand.command);
assertTrue(response.result);
assertEquals(Long.valueOf(1028), response.getNumericAttribute(SOURCE_ID));
assertEquals(Long.valueOf(3), response.getNumericAttribute(RETURNED));
assertEquals(Long.valueOf(3), response.getNumericAttribute(COUNT));
BrowseResult result = response.payload[0];
BrowseResult[] payload = response.payload;
assertNotNull(payload);
BrowseResult result = payload[0];
assertEquals(YesNoEnum.NO, result.container);
assertEquals("s6707", result.mediaId);
@@ -288,7 +331,7 @@ public class HeosJsonParserResponseTest {
}
@Test
public void get_groups() {
public void getGroups() {
HeosResponseObject<Group[]> response = subject.parseResponse(
"""
{"heos": {"command": "group/get_groups", "result": "success", "message": ""}, "payload": [ \
@@ -297,11 +340,15 @@ public class HeosJsonParserResponseTest {
""",
Group[].class);
assertEquals(HeosCommandGroup.GROUP, response.heosCommand.commandGroup);
assertEquals(HeosCommand.GET_GROUPS, response.heosCommand.command);
HeosCommandTuple heosCommand = response.heosCommand;
assertNotNull(heosCommand);
assertEquals(HeosCommandGroup.GROUP, heosCommand.commandGroup);
assertEquals(HeosCommand.GET_GROUPS, heosCommand.command);
assertTrue(response.result);
Group group = response.payload[0];
Group[] payload = response.payload;
assertNotNull(payload);
Group group = payload[0];
assertEquals("Group 1", group.name);
assertEquals("214243242", group.id);