[denonmarantz] Add null annotations (#16757)

* Add null annotations

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Jacob Laursen 2024-05-13 22:51:04 +02:00 committed by Ciprian Pascu
parent 30bf2375fd
commit 19d6436ab6
27 changed files with 217 additions and 152 deletions

View File

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.type.ChannelTypeUID;
@ -26,6 +27,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
*
* @author Jan-Willem Veldhuis - Initial contribution
*/
@NonNullByDefault
public class DenonMarantzBindingConstants {
public static final String BINDING_ID = "denonmarantz";

View File

@ -14,6 +14,8 @@ package org.openhab.binding.denonmarantz.internal;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
@ -26,38 +28,39 @@ import org.openhab.core.types.State;
* @author Jan-Willem Veldhuis - Initial contribution
*
*/
@NonNullByDefault
public class DenonMarantzState {
private State power;
private State mainZonePower;
private State mute;
private State mainVolume;
private State mainVolumeDB;
private State input;
private State surroundProgram;
private @Nullable State power;
private @Nullable State mainZonePower;
private @Nullable State mute;
private @Nullable State mainVolume;
private @Nullable State mainVolumeDB;
private @Nullable State input;
private @Nullable State surroundProgram;
private State artist;
private State album;
private State track;
private @Nullable State artist;
private @Nullable State album;
private @Nullable State track;
// ------ Zones ------
private State zone2Power;
private State zone2Volume;
private State zone2VolumeDB;
private State zone2Mute;
private State zone2Input;
private @Nullable State zone2Power;
private @Nullable State zone2Volume;
private @Nullable State zone2VolumeDB;
private @Nullable State zone2Mute;
private @Nullable State zone2Input;
private State zone3Power;
private State zone3Volume;
private State zone3VolumeDB;
private State zone3Mute;
private State zone3Input;
private @Nullable State zone3Power;
private @Nullable State zone3Volume;
private @Nullable State zone3VolumeDB;
private @Nullable State zone3Mute;
private @Nullable State zone3Input;
private State zone4Power;
private State zone4Volume;
private State zone4VolumeDB;
private State zone4Mute;
private State zone4Input;
private @Nullable State zone4Power;
private @Nullable State zone4Volume;
private @Nullable State zone4VolumeDB;
private @Nullable State zone4Mute;
private @Nullable State zone4Input;
private DenonMarantzStateChangedListener handler;
@ -69,7 +72,7 @@ public class DenonMarantzState {
handler.connectionError(errorMessage);
}
public State getStateForChannelID(String channelID) {
public @Nullable State getStateForChannelID(String channelID) {
switch (channelID) {
case DenonMarantzBindingConstants.CHANNEL_POWER:
return power;
@ -135,7 +138,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(power);
if (newVal != this.power) {
this.power = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_POWER, this.power);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_POWER, newVal);
}
}
@ -143,7 +146,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(mainPower);
if (newVal != this.mainZonePower) {
this.mainZonePower = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_ZONE_POWER, this.mainZonePower);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_ZONE_POWER, newVal);
}
}
@ -151,7 +154,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(mute);
if (newVal != this.mute) {
this.mute = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MUTE, this.mute);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MUTE, newVal);
}
}
@ -159,10 +162,11 @@ public class DenonMarantzState {
PercentType newVal = new PercentType(volume);
if (!newVal.equals(this.mainVolume)) {
this.mainVolume = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_VOLUME, this.mainVolume);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_VOLUME, newVal);
// update the main volume in dB too
this.mainVolumeDB = DecimalType.valueOf(volume.subtract(DenonMarantzBindingConstants.DB_OFFSET).toString());
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_VOLUME_DB, this.mainVolumeDB);
State mainVolumeDB = this.mainVolumeDB = DecimalType
.valueOf(volume.subtract(DenonMarantzBindingConstants.DB_OFFSET).toString());
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_MAIN_VOLUME_DB, mainVolumeDB);
}
}
@ -170,7 +174,7 @@ public class DenonMarantzState {
StringType newVal = StringType.valueOf(input);
if (!newVal.equals(this.input)) {
this.input = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_INPUT, this.input);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_INPUT, newVal);
}
}
@ -178,31 +182,31 @@ public class DenonMarantzState {
StringType newVal = StringType.valueOf(surroundProgram);
if (!newVal.equals(this.surroundProgram)) {
this.surroundProgram = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_SURROUND_PROGRAM, this.surroundProgram);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_SURROUND_PROGRAM, newVal);
}
}
public void setNowPlayingArtist(String artist) {
StringType newVal = artist == null || artist.isBlank() ? StringType.EMPTY : StringType.valueOf(artist);
StringType newVal = artist.isBlank() ? StringType.EMPTY : StringType.valueOf(artist);
if (!newVal.equals(this.artist)) {
this.artist = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_ARTIST, this.artist);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_ARTIST, newVal);
}
}
public void setNowPlayingAlbum(String album) {
StringType newVal = album == null || album.isBlank() ? StringType.EMPTY : StringType.valueOf(album);
StringType newVal = album.isBlank() ? StringType.EMPTY : StringType.valueOf(album);
if (!newVal.equals(this.album)) {
this.album = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_ALBUM, this.album);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_ALBUM, newVal);
}
}
public void setNowPlayingTrack(String track) {
StringType newVal = track == null || track.isBlank() ? StringType.EMPTY : StringType.valueOf(track);
StringType newVal = track.isBlank() ? StringType.EMPTY : StringType.valueOf(track);
if (!newVal.equals(this.track)) {
this.track = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_TRACK, this.track);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_NOW_PLAYING_TRACK, newVal);
}
}
@ -210,7 +214,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(power);
if (newVal != this.zone2Power) {
this.zone2Power = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_POWER, this.zone2Power);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_POWER, newVal);
}
}
@ -218,11 +222,11 @@ public class DenonMarantzState {
PercentType newVal = new PercentType(volume);
if (!newVal.equals(this.zone2Volume)) {
this.zone2Volume = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_VOLUME, this.zone2Volume);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_VOLUME, newVal);
// update the volume in dB too
this.zone2VolumeDB = DecimalType
State zone2VolumeDB = this.zone2VolumeDB = DecimalType
.valueOf(volume.subtract(DenonMarantzBindingConstants.DB_OFFSET).toString());
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_VOLUME_DB, this.zone2VolumeDB);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_VOLUME_DB, zone2VolumeDB);
}
}
@ -230,7 +234,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(mute);
if (newVal != this.zone2Mute) {
this.zone2Mute = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_MUTE, this.zone2Mute);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_MUTE, newVal);
}
}
@ -238,7 +242,7 @@ public class DenonMarantzState {
StringType newVal = StringType.valueOf(zone2Input);
if (!newVal.equals(this.zone2Input)) {
this.zone2Input = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_INPUT, this.zone2Input);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_INPUT, newVal);
}
}
@ -246,7 +250,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(power);
if (newVal != this.zone3Power) {
this.zone3Power = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_POWER, this.zone3Power);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_POWER, newVal);
}
}
@ -254,11 +258,11 @@ public class DenonMarantzState {
PercentType newVal = new PercentType(volume);
if (!newVal.equals(this.zone3Volume)) {
this.zone3Volume = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_VOLUME, this.zone3Volume);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_VOLUME, newVal);
// update the volume in dB too
this.zone3VolumeDB = DecimalType
State zone3VolumeDB = this.zone3VolumeDB = DecimalType
.valueOf(volume.subtract(DenonMarantzBindingConstants.DB_OFFSET).toString());
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_VOLUME_DB, this.zone3VolumeDB);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_VOLUME_DB, zone3VolumeDB);
}
}
@ -266,7 +270,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(mute);
if (newVal != this.zone3Mute) {
this.zone3Mute = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_MUTE, this.zone3Mute);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE3_MUTE, newVal);
}
}
@ -274,7 +278,7 @@ public class DenonMarantzState {
StringType newVal = StringType.valueOf(zone3Input);
if (!newVal.equals(this.zone3Input)) {
this.zone3Input = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_INPUT, this.zone3Input);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE2_INPUT, newVal);
}
}
@ -282,7 +286,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(power);
if (newVal != this.zone4Power) {
this.zone4Power = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_POWER, this.zone4Power);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_POWER, newVal);
}
}
@ -290,11 +294,11 @@ public class DenonMarantzState {
PercentType newVal = new PercentType(volume);
if (!newVal.equals(this.zone4Volume)) {
this.zone4Volume = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_VOLUME, this.zone4Volume);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_VOLUME, newVal);
// update the volume in dB too
this.zone4VolumeDB = DecimalType
State zone4VolumeDB = this.zone4VolumeDB = DecimalType
.valueOf(volume.subtract(DenonMarantzBindingConstants.DB_OFFSET).toString());
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_VOLUME_DB, this.zone4VolumeDB);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_VOLUME_DB, zone4VolumeDB);
}
}
@ -302,7 +306,7 @@ public class DenonMarantzState {
OnOffType newVal = OnOffType.from(mute);
if (newVal != this.zone4Mute) {
this.zone4Mute = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_MUTE, this.zone4Mute);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_MUTE, newVal);
}
}
@ -310,7 +314,7 @@ public class DenonMarantzState {
StringType newVal = StringType.valueOf(zone4Input);
if (!newVal.equals(this.zone4Input)) {
this.zone4Input = newVal;
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_INPUT, this.zone4Input);
handler.stateChanged(DenonMarantzBindingConstants.CHANNEL_ZONE4_INPUT, newVal);
}
}
}

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.denonmarantz.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Exception thrown when an unsupported command type is sent to a channel.
*
* @author Jan-Willem Veldhuis - Initial contribution
*
*/
@NonNullByDefault
public class UnsupportedCommandTypeException extends Exception {
private static final long serialVersionUID = 42L;

View File

@ -15,7 +15,8 @@ package org.openhab.binding.denonmarantz.internal.config;
import java.math.BigDecimal;
import java.util.List;
import org.openhab.binding.denonmarantz.internal.connector.DenonMarantzConnector;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Configuration class for the Denon Marantz binding.
@ -23,43 +24,42 @@ import org.openhab.binding.denonmarantz.internal.connector.DenonMarantzConnector
* @author Jan-Willem Veldhuis - Initial contribution
*
*/
@NonNullByDefault
public class DenonMarantzConfiguration {
/**
* The hostname (or IP Address) of the Denon Marantz AVR
*/
public String host;
public String host = "";
/**
* Whether Telnet communication is enabled
*/
public Boolean telnetEnabled;
public @Nullable Boolean telnetEnabled;
/**
* The telnet port
*/
public Integer telnetPort;
public Integer telnetPort = 23;
/**
* The HTTP port
*/
public Integer httpPort;
public Integer httpPort = 80;
/**
* The interval to poll the AVR over HTTP for changes
*/
public Integer httpPollingInterval;
public Integer httpPollingInterval = 5;
// Default maximum volume
public static final BigDecimal MAX_VOLUME = new BigDecimal("98");
private DenonMarantzConnector connector;
private Integer zoneCount;
private Integer zoneCount = 2;
private BigDecimal mainVolumeMax = MAX_VOLUME;
public List<String> inputOptions;
public @Nullable List<String> inputOptions;
public String getHost() {
return host;
@ -69,7 +69,7 @@ public class DenonMarantzConfiguration {
this.host = host;
}
public Boolean isTelnet() {
public @Nullable Boolean isTelnet() {
return telnetEnabled;
}
@ -93,14 +93,6 @@ public class DenonMarantzConfiguration {
this.httpPort = httpPort;
}
public DenonMarantzConnector getConnector() {
return connector;
}
public void setConnector(DenonMarantzConnector connector) {
this.connector = connector;
}
public BigDecimal getMainVolumeMax() {
return mainVolumeMax;
}

View File

@ -18,6 +18,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
import org.openhab.binding.denonmarantz.internal.UnsupportedCommandTypeException;
import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
@ -34,6 +35,7 @@ import org.openhab.core.types.RefreshType;
*
* @author Jan-Willem Veldhuis - Initial contribution
*/
@NonNullByDefault
public abstract class DenonMarantzConnector {
private static final BigDecimal POINTFIVE = new BigDecimal("0.5");
@ -47,6 +49,13 @@ public abstract class DenonMarantzConnector {
protected abstract void internalSendCommand(String command);
public DenonMarantzConnector(DenonMarantzConfiguration config, ScheduledExecutorService scheduler,
DenonMarantzState state) {
this.config = config;
this.scheduler = scheduler;
this.state = state;
}
public void sendCustomCommand(Command command) throws UnsupportedCommandTypeException {
String cmd;
if (command instanceof StringType) {

View File

@ -14,6 +14,7 @@ package org.openhab.binding.denonmarantz.internal.connector;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
@ -26,11 +27,13 @@ import org.openhab.binding.denonmarantz.internal.connector.telnet.DenonMarantzTe
*
* @author Jan-Willem Veldhuis - Initial contribution
*/
@NonNullByDefault
public class DenonMarantzConnectorFactory {
public DenonMarantzConnector getConnector(DenonMarantzConfiguration config, DenonMarantzState state,
ScheduledExecutorService scheduler, HttpClient httpClient, String thingUID) {
if (config.isTelnet()) {
Boolean isTelnet = config.isTelnet();
if (isTelnet != null && isTelnet) {
return new DenonMarantzTelnetConnector(config, state, scheduler, thingUID);
} else {
return new DenonMarantzHttpConnector(config, state, scheduler, httpClient);

View File

@ -32,6 +32,7 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Response;
@ -39,14 +40,14 @@ import org.eclipse.jetty.client.api.Result;
import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
import org.openhab.binding.denonmarantz.internal.connector.DenonMarantzConnector;
import org.openhab.binding.denonmarantz.internal.xml.entities.Deviceinfo;
import org.openhab.binding.denonmarantz.internal.xml.entities.Main;
import org.openhab.binding.denonmarantz.internal.xml.entities.ZoneStatus;
import org.openhab.binding.denonmarantz.internal.xml.entities.ZoneStatusLite;
import org.openhab.binding.denonmarantz.internal.xml.entities.commands.AppCommandRequest;
import org.openhab.binding.denonmarantz.internal.xml.entities.commands.AppCommandResponse;
import org.openhab.binding.denonmarantz.internal.xml.entities.commands.CommandRx;
import org.openhab.binding.denonmarantz.internal.xml.entities.commands.CommandTx;
import org.openhab.binding.denonmarantz.internal.xml.dto.Deviceinfo;
import org.openhab.binding.denonmarantz.internal.xml.dto.Main;
import org.openhab.binding.denonmarantz.internal.xml.dto.ZoneStatus;
import org.openhab.binding.denonmarantz.internal.xml.dto.ZoneStatusLite;
import org.openhab.binding.denonmarantz.internal.xml.dto.commands.AppCommandRequest;
import org.openhab.binding.denonmarantz.internal.xml.dto.commands.AppCommandResponse;
import org.openhab.binding.denonmarantz.internal.xml.dto.commands.CommandRx;
import org.openhab.binding.denonmarantz.internal.xml.dto.commands.CommandTx;
import org.openhab.core.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -59,6 +60,7 @@ import org.slf4j.LoggerFactory;
* @author Jeroen Idserda - Initial Contribution (1.x Binding)
* @author Jan-Willem Veldhuis - Refactored for 2.x
*/
@NonNullByDefault
public class DenonMarantzHttpConnector extends DenonMarantzConnector {
private Logger logger = LoggerFactory.getLogger(DenonMarantzHttpConnector.class);
@ -88,13 +90,11 @@ public class DenonMarantzHttpConnector extends DenonMarantzConnector {
private final HttpClient httpClient;
private ScheduledFuture<?> pollingJob;
private @Nullable ScheduledFuture<?> pollingJob;
public DenonMarantzHttpConnector(DenonMarantzConfiguration config, DenonMarantzState state,
ScheduledExecutorService scheduler, HttpClient httpClient) {
this.config = config;
this.scheduler = scheduler;
this.state = state;
super(config, scheduler, state);
this.cmdUrl = String.format("http://%s:%d/goform/formiPhoneAppDirect.xml?", config.getHost(),
config.getHttpPort());
this.statusUrl = String.format("http://%s:%d/goform/", config.getHost(), config.getHttpPort());
@ -143,11 +143,13 @@ public class DenonMarantzHttpConnector extends DenonMarantzConnector {
}
private boolean isPolling() {
ScheduledFuture<?> pollingJob = this.pollingJob;
return pollingJob != null && !pollingJob.isCancelled();
}
private void stopPolling() {
if (isPolling()) {
ScheduledFuture<?> pollingJob = this.pollingJob;
if (pollingJob != null) {
pollingJob.cancel(true);
logger.debug("HTTP polling stopped.");
}
@ -166,7 +168,7 @@ public class DenonMarantzHttpConnector extends DenonMarantzConnector {
@Override
protected void internalSendCommand(String command) {
logger.debug("Sending command '{}'", command);
if (command == null || command.isBlank()) {
if (command.isBlank()) {
logger.warn("Trying to send empty command");
return;
}
@ -176,8 +178,8 @@ public class DenonMarantzHttpConnector extends DenonMarantzConnector {
httpClient.newRequest(url).timeout(5, TimeUnit.SECONDS).send(new Response.CompleteListener() {
@Override
public void onComplete(Result result) {
if (result.getResponse().getStatus() != 200) {
public void onComplete(@Nullable Result result) {
if (result != null && result.getResponse().getStatus() != 200) {
logger.warn("Error {} while sending command", result.getResponse().getReason());
}
}
@ -255,11 +257,21 @@ public class DenonMarantzHttpConnector extends DenonMarantzConnector {
AppCommandRequest request = AppCommandRequest.of(CommandTx.CMD_NET_STATUS);
AppCommandResponse response = postDocument(url, AppCommandResponse.class, request);
if (response != null) {
CommandRx titleInfo = response.getCommands().get(0);
state.setNowPlayingArtist(titleInfo.getText("artist"));
state.setNowPlayingAlbum(titleInfo.getText("album"));
state.setNowPlayingTrack(titleInfo.getText("track"));
if (response == null) {
return;
}
CommandRx titleInfo = response.getCommands().get(0);
String artist = titleInfo.getText("artist");
if (artist != null) {
state.setNowPlayingArtist(artist);
}
String album = titleInfo.getText("album");
if (album != null) {
state.setNowPlayingAlbum(album);
}
String track = titleInfo.getText("track");
if (track != null) {
state.setNowPlayingTrack(track);
}
}

View File

@ -20,6 +20,7 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
import org.slf4j.Logger;
@ -31,6 +32,7 @@ import org.slf4j.LoggerFactory;
* @author Jeroen Idserda - Initial contribution (1.x Binding)
* @author Jan-Willem Veldhuis - Refactored for 2.x
*/
@NonNullByDefault
public class DenonMarantzTelnetClientThread extends Thread {
private Logger logger = LoggerFactory.getLogger(DenonMarantzTelnetClientThread.class);
@ -45,9 +47,9 @@ public class DenonMarantzTelnetClientThread extends Thread {
private boolean connected = false;
private Socket socket;
private @Nullable Socket socket;
private OutputStreamWriter out;
private @Nullable OutputStreamWriter out;
private @Nullable BufferedReader in;
@ -84,12 +86,15 @@ public class DenonMarantzTelnetClientThread extends Thread {
} catch (SocketTimeoutException e) {
logger.trace("Socket timeout");
// Disconnects are not always detected unless you write to the socket.
try {
out.write('\r');
out.flush();
} catch (IOException e2) {
logger.debug("Error writing to socket");
connected = false;
OutputStreamWriter out = this.out;
if (out != null) {
try {
out.write('\r');
out.flush();
} catch (IOException e2) {
logger.debug("Error writing to socket");
connected = false;
}
}
} catch (IOException e) {
if (!isInterrupted()) {
@ -106,6 +111,7 @@ public class DenonMarantzTelnetClientThread extends Thread {
}
public void sendCommand(String command) {
OutputStreamWriter out = this.out;
if (out != null) {
try {
out.write(command + '\r');
@ -126,6 +132,7 @@ public class DenonMarantzTelnetClientThread extends Thread {
disconnect();
int delay = 0;
Socket socket = this.socket;
while (!isInterrupted() && (socket == null || !socket.isConnected())) {
try {
Thread.sleep(delay);
@ -134,7 +141,7 @@ public class DenonMarantzTelnetClientThread extends Thread {
// Use raw socket instead of TelnetClient here because TelnetClient sends an
// extra newline char after each write which causes the connection to become
// unresponsive.
socket = new Socket();
socket = this.socket = new Socket();
socket.connect(new InetSocketAddress(config.getHost(), config.getTelnetPort()), TIMEOUT);
socket.setKeepAlive(true);
socket.setSoTimeout(TIMEOUT);
@ -161,6 +168,7 @@ public class DenonMarantzTelnetClientThread extends Thread {
}
private void disconnect() {
Socket socket = this.socket;
if (socket != null) {
logger.debug("Disconnecting socket");
try {
@ -168,7 +176,7 @@ public class DenonMarantzTelnetClientThread extends Thread {
} catch (IOException e) {
logger.debug("Error while disconnecting telnet client", e);
} finally {
socket = null;
this.socket = null;
out = null;
in = null;
listener.telnetClientConnected(false);

View File

@ -20,6 +20,8 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
import org.openhab.binding.denonmarantz.internal.connector.DenonMarantzConnector;
@ -33,6 +35,7 @@ import org.slf4j.LoggerFactory;
* @author Jeroen Idserda - Initial Contribution (1.x Binding)
* @author Jan-Willem Veldhuis - Refactored for 2.x
*/
@NonNullByDefault
public class DenonMarantzTelnetConnector extends DenonMarantzConnector implements DenonMarantzTelnetListener {
private final Logger logger = LoggerFactory.getLogger(DenonMarantzTelnetConnector.class);
@ -45,21 +48,19 @@ public class DenonMarantzTelnetConnector extends DenonMarantzConnector implement
private static final BigDecimal NINETYNINE = new BigDecimal("99");
private DenonMarantzTelnetClientThread telnetClientThread;
private @Nullable DenonMarantzTelnetClientThread telnetClientThread;
private boolean displayNowplaying = false;
protected boolean disposing = false;
private Future<?> telnetStateRequest;
private @Nullable Future<?> telnetStateRequest;
private String thingUID;
public DenonMarantzTelnetConnector(DenonMarantzConfiguration config, DenonMarantzState state,
ScheduledExecutorService scheduler, String thingUID) {
this.config = config;
this.scheduler = scheduler;
this.state = state;
super(config, scheduler, state);
this.thingUID = thingUID;
}
@ -68,7 +69,8 @@ public class DenonMarantzTelnetConnector extends DenonMarantzConnector implement
*/
@Override
public void connect() {
telnetClientThread = new DenonMarantzTelnetClientThread(config, this);
DenonMarantzTelnetClientThread telnetClientThread = this.telnetClientThread = new DenonMarantzTelnetClientThread(
config, this);
telnetClientThread.setName("OH-binding-" + thingUID);
telnetClientThread.start();
}
@ -76,7 +78,8 @@ public class DenonMarantzTelnetConnector extends DenonMarantzConnector implement
@Override
public void telnetClientConnected(boolean connected) {
if (!connected) {
if (config.isTelnet() && !disposing) {
Boolean isTelnet = config.isTelnet();
if (isTelnet != null && isTelnet && !disposing) {
logger.debug("Telnet client disconnected.");
state.connectionError(
"Error connecting to the telnet port. Consider disabling telnet in this Thing's configuration to use HTTP polling instead.");
@ -94,17 +97,19 @@ public class DenonMarantzTelnetConnector extends DenonMarantzConnector implement
logger.debug("disposing connector");
disposing = true;
Future<?> telnetStateRequest = this.telnetStateRequest;
if (telnetStateRequest != null) {
telnetStateRequest.cancel(true);
telnetStateRequest = null;
this.telnetStateRequest = null;
}
DenonMarantzTelnetClientThread telnetClientThread = this.telnetClientThread;
if (telnetClientThread != null) {
telnetClientThread.interrupt();
// Invoke a shutdown after interrupting the thread to close the socket immediately,
// otherwise the client keeps running until a line was received from the telnet connection
telnetClientThread.shutdown();
telnetClientThread = null;
this.telnetClientThread = null;
}
}
@ -263,11 +268,14 @@ public class DenonMarantzTelnetConnector extends DenonMarantzConnector implement
@Override
protected void internalSendCommand(String command) {
logger.debug("Sending command '{}'", command);
if (command == null || command.isBlank()) {
if (command.isBlank()) {
logger.warn("Trying to send empty command");
return;
}
telnetClientThread.sendCommand(command);
DenonMarantzTelnetClientThread telnetClientThread = this.telnetClientThread;
if (telnetClientThread != null) {
telnetClientThread.sendCommand(command);
}
}
/**

View File

@ -12,6 +12,8 @@
*/
package org.openhab.binding.denonmarantz.internal.connector.telnet;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Listener interface used to notify the
* {@link org.openhab.binding.denonmarantz.internal.connector.DenonMarantzConnector} about received messages over Telnet
@ -19,6 +21,7 @@ package org.openhab.binding.denonmarantz.internal.connector.telnet;
* @author Jan-Willem Veldhuis - Initial contribution
*
*/
@NonNullByDefault
public interface DenonMarantzTelnetListener {
/**
* The telnet client has received a line.

View File

@ -14,15 +14,19 @@ package org.openhab.binding.denonmarantz.internal.xml.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Maps 'On' and 'Off' string values to a boolean
*
* @author Jeroen Idserda - Initial contribution
*/
public class OnOffAdapter extends XmlAdapter<String, Boolean> {
@NonNullByDefault
public class OnOffAdapter extends XmlAdapter<@Nullable String, @Nullable Boolean> {
@Override
public Boolean unmarshal(String v) throws Exception {
public @Nullable Boolean unmarshal(@Nullable String v) throws Exception {
if (v != null) {
return Boolean.valueOf("on".equals(v.toLowerCase()));
}
@ -31,7 +35,7 @@ public class OnOffAdapter extends XmlAdapter<String, Boolean> {
}
@Override
public String marshal(Boolean v) throws Exception {
public @Nullable String marshal(@Nullable Boolean v) throws Exception {
return v ? "On" : "Off";
}
}

View File

@ -14,15 +14,19 @@ package org.openhab.binding.denonmarantz.internal.xml.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Adapter to clean up string values
*
* @author Jeroen Idserda - Initial contribution
*/
public class StringAdapter extends XmlAdapter<String, String> {
@NonNullByDefault
public class StringAdapter extends XmlAdapter<@Nullable String, @Nullable String> {
@Override
public String unmarshal(String v) throws Exception {
public @Nullable String unmarshal(@Nullable String v) throws Exception {
String val = v;
if (val != null) {
return val.trim();
@ -31,7 +35,7 @@ public class StringAdapter extends XmlAdapter<String, String> {
}
@Override
public String marshal(String v) throws Exception {
public @Nullable String marshal(@Nullable String v) throws Exception {
return v;
}
}

View File

@ -18,15 +18,19 @@ import java.math.BigDecimal;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Maps Denon volume values in db to percentage
*
* @author Jeroen Idserda - Initial contribution
*/
public class VolumeAdapter extends XmlAdapter<String, BigDecimal> {
@NonNullByDefault
public class VolumeAdapter extends XmlAdapter<@Nullable String, BigDecimal> {
@Override
public BigDecimal unmarshal(String v) throws Exception {
public BigDecimal unmarshal(@Nullable String v) throws Exception {
if (v != null && !"--".equals(v.trim())) {
return new BigDecimal(v.trim()).add(DB_OFFSET);
}
@ -35,7 +39,7 @@ public class VolumeAdapter extends XmlAdapter<String, BigDecimal> {
}
@Override
public String marshal(BigDecimal v) throws Exception {
public @Nullable String marshal(BigDecimal v) throws Exception {
if (v.equals(BigDecimal.ZERO)) {
return "--";
}

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities;
package org.openhab.binding.denonmarantz.internal.xml.dto;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,13 +10,13 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities;
package org.openhab.binding.denonmarantz.internal.xml.dto;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.OnOffType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.OnOffType;
/**
* Holds information about the Main zone of the receiver

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities;
package org.openhab.binding.denonmarantz.internal.xml.dto;
import java.util.List;
@ -20,9 +20,9 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.OnOffType;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.StringType;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.VolumeType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.OnOffType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.StringType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.VolumeType;
/**
* Holds information about the secondary zones of the receiver

View File

@ -10,15 +10,15 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities;
package org.openhab.binding.denonmarantz.internal.xml.dto;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.OnOffType;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.StringType;
import org.openhab.binding.denonmarantz.internal.xml.entities.types.VolumeType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.OnOffType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.StringType;
import org.openhab.binding.denonmarantz.internal.xml.dto.types.VolumeType;
/**
* Holds limited information about the secondary zones of the receiver

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import java.util.ArrayList;
import java.util.List;
@ -20,6 +20,8 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Wrapper for a list of {@link CommandTx}
*
@ -27,6 +29,7 @@ import javax.xml.bind.annotation.XmlRootElement;
*/
@XmlRootElement(name = "tx")
@XmlAccessorType(XmlAccessType.FIELD)
@NonNullByDefault
public class AppCommandRequest {
@XmlElement(name = "cmd")

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import java.util.ArrayList;
import java.util.List;
@ -20,6 +20,8 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Response to an {@link AppCommandRequest}, wraps a list of {@link CommandRx}
*
@ -27,6 +29,7 @@ import javax.xml.bind.annotation.XmlRootElement;
*/
@XmlRootElement(name = "rx")
@XmlAccessorType(XmlAccessType.FIELD)
@NonNullByDefault
public class AppCommandResponse {
@XmlElement(name = "cmd")

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import java.util.ArrayList;
import java.util.List;
@ -21,6 +21,9 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
/**
* Response to a {@link CommandTx}
*
@ -184,9 +187,9 @@ public class CommandRx {
this.source = source;
}
public String getText(String key) {
public @Nullable String getText(@NonNull String key) {
for (Text text : texts) {
if (text.getId().equals(key)) {
if (key.equals(text.getId())) {
return text.getValue();
}
}

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.commands;
package org.openhab.binding.denonmarantz.internal.xml.dto.commands;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.types;
package org.openhab.binding.denonmarantz.internal.xml.dto.types;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.types;
package org.openhab.binding.denonmarantz.internal.xml.dto.types;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.denonmarantz.internal.xml.entities.types;
package org.openhab.binding.denonmarantz.internal.xml.dto.types;
import java.math.BigDecimal;