[emotiva] Improve logging, retry job, static typing and type inference. (#17596)

* Add and improve logging when trying to map channel change to Emotiva Control Commands.
* Improve logging of notifications and keep alive job.
* Improve checking of retry job status.
* Improve static typing of previous state.
* Use type inference in selected places.

Signed-off-by: Espen Fossen <espenaf@junta.no>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Espen Fossen 2024-10-28 19:10:41 +01:00 committed by Ciprian Pascu
parent 7a45a6156a
commit 29cca2cdac
32 changed files with 357 additions and 219 deletions

View File

@ -52,9 +52,6 @@ public class EmotivaBindingConstants {
*/
static final int DEFAULT_KEEP_ALIVE_IN_MILLISECONDS = 7500;
/** State name for storing keepAlive timestamp messages */
public static final String LAST_SEEN_STATE_NAME = "no-channel#last-seen";
/**
* Default Emotiva device considered list in milliseconds.
* {@link org.openhab.binding.emotiva.internal.dto.ControlDTO}

View File

@ -94,7 +94,7 @@ public class EmotivaCommandHelper {
public static String updateProgress(double progressPercentage) {
final int width = 30;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.append("[");
int i = 0;

View File

@ -25,6 +25,7 @@ import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlComman
import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.STRING;
import static org.openhab.binding.emotiva.internal.protocol.EmotivaPropertyStatus.NOT_VALID;
import static org.openhab.binding.emotiva.internal.protocol.EmotivaProtocolVersion.protocolFromConfig;
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags.keepAlive;
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags.noSubscriptionToChannel;
import java.io.IOException;
@ -33,6 +34,8 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.EnumMap;
@ -52,7 +55,9 @@ import org.openhab.binding.emotiva.internal.dto.EmotivaAckDTO;
import org.openhab.binding.emotiva.internal.dto.EmotivaBarNotifyDTO;
import org.openhab.binding.emotiva.internal.dto.EmotivaBarNotifyWrapper;
import org.openhab.binding.emotiva.internal.dto.EmotivaControlDTO;
import org.openhab.binding.emotiva.internal.dto.EmotivaMenuCol;
import org.openhab.binding.emotiva.internal.dto.EmotivaMenuNotifyDTO;
import org.openhab.binding.emotiva.internal.dto.EmotivaMenuRow;
import org.openhab.binding.emotiva.internal.dto.EmotivaNotifyDTO;
import org.openhab.binding.emotiva.internal.dto.EmotivaNotifyWrapper;
import org.openhab.binding.emotiva.internal.dto.EmotivaPropertyDTO;
@ -81,6 +86,7 @@ import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -134,7 +140,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
@Override
public void initialize() {
logger.debug("Initialize: '{}'", getThing().getUID());
logger.debug("Initialize: '{}'", thing.getUID());
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "@text/message.processor.connecting");
if (config.controlPort < 0) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
@ -162,12 +168,11 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
private synchronized void connect() {
final EmotivaConfiguration localConfig = config;
try {
final EmotivaUdpReceivingService notifyListener = new EmotivaUdpReceivingService(localConfig.notifyPort,
localConfig, scheduler);
final var notifyListener = new EmotivaUdpReceivingService(localConfig.notifyPort, localConfig, scheduler);
this.notifyListener = notifyListener;
notifyListener.connect(this::handleStatusUpdate, true);
final EmotivaUdpSendingService sendConnector = new EmotivaUdpSendingService(localConfig, scheduler);
final var sendConnector = new EmotivaUdpSendingService(localConfig, scheduler);
sendingService = sendConnector;
sendConnector.connect(this::handleStatusUpdate, true);
@ -189,13 +194,13 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
if (udpSenderActive) {
updateStatus(ThingStatus.ONLINE);
state.updateLastSeen(ZonedDateTime.now(ZoneId.systemDefault()).toInstant());
startPollingKeepAlive();
final EmotivaUdpReceivingService menuListenerConnector = new EmotivaUdpReceivingService(
localConfig.menuNotifyPort, localConfig, scheduler);
final var menuListenerConnector = new EmotivaUdpReceivingService(localConfig.menuNotifyPort,
localConfig, scheduler);
this.menuNotifyListener = menuListenerConnector;
menuListenerConnector.connect(this::handleStatusUpdate, true);
startPollingKeepAlive();
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"@text/message.processor.connection.failed");
@ -241,37 +246,64 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
private void checkKeepAliveTimestamp() {
if (ThingStatus.ONLINE.equals(getThing().getStatusInfo().getStatus())) {
Optional<State> lastSeenState = state.getChannel(LAST_SEEN_STATE_NAME);
if (lastSeenState.isPresent()) {
if (lastSeenState.get() instanceof Number value) {
Instant lastKeepAliveMessageTimestamp = Instant.ofEpochSecond(value.longValue());
Instant deviceGoneGracePeriod = Instant.now().minus(config.keepAlive, ChronoUnit.MILLIS)
.minus(DEFAULT_KEEP_ALIVE_CONSIDERED_LOST_IN_MILLISECONDS, ChronoUnit.MILLIS);
if (lastKeepAliveMessageTimestamp.isBefore(deviceGoneGracePeriod)) {
Instant lastKeepAliveTimestamp = state.getLastSeen();
Instant deviceGoneGracePeriod = Instant.now().minus(config.keepAlive, ChronoUnit.MILLIS)
.minus(DEFAULT_KEEP_ALIVE_CONSIDERED_LOST_IN_MILLISECONDS, ChronoUnit.MILLIS);
boolean isPastGradePeriod = lastKeepAliveTimestamp.isBefore(deviceGoneGracePeriod);
if (ThingStatus.ONLINE.equals(thing.getStatusInfo().getStatus())) {
if (isPastGradePeriod) {
logger.debug(
"Keep-alive job for '{}': status={}, last-seen was '{}', past grace-period by '{}', scheduling connection retry",
thing.getUID(), thing.getStatusInfo().getStatus(), lastKeepAliveTimestamp,
Duration.between(lastKeepAliveTimestamp, deviceGoneGracePeriod));
setOfflineAndScheduleConnectRetry();
}
} else {
try {
ScheduledFuture<?> localConnectRetryJob = connectRetryJob;
if (localConnectRetryJob == null || localConnectRetryJob.isCancelled()) {
logger.debug(
"Keep-alive job for '{}': status={}, no active retry job, scheduling new connection retry",
thing.getUID(), thing.getStatusInfo().getStatus());
setOfflineAndScheduleConnectRetry();
} else {
Duration currentJobDelay = Duration.of(localConnectRetryJob.getDelay(TimeUnit.SECONDS),
ChronoUnit.SECONDS);
Duration defaultJobDelay = Duration.of(DEFAULT_RETRY_INTERVAL_MINUTES, ChronoUnit.MINUTES);
if (defaultJobDelay.minus(currentJobDelay).isNegative()) {
logger.debug(
"Last KeepAlive message received '{}', over grace-period by '{}', consider '{}' gone, setting OFFLINE and disposing",
lastKeepAliveMessageTimestamp,
Duration.between(lastKeepAliveMessageTimestamp, deviceGoneGracePeriod),
thing.getThingTypeUID());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/message.processor.connection.error.keep-alive");
// Connection lost, avoid sending unsubscription messages
udpSenderActive = false;
disconnect();
scheduleConnectRetry(retryConnectInMinutes);
"Keep-alive job for '{}': status={}, retry job not working, canceling and scheduling new connection retry",
thing.getUID(), thing.getStatusInfo().getStatus());
// Kill current connection retry job and schedule a new one
localConnectRetryJob.cancel(true);
setOfflineAndScheduleConnectRetry();
} else {
logger.debug("Keep-alive job for '{}': status={}, retry job still scheduled, nothing to do",
thing.getUID(), thing.getStatusInfo().getStatus());
}
}
} catch (Exception e) {
logger.debug("Keep-alive job for '{}': status={}, failed checking connection retry job with '{}'",
thing.getUID(), thing.getStatusInfo().getStatus(), e.getMessage());
}
} else if (ThingStatus.OFFLINE.equals(getThing().getStatusInfo().getStatus())) {
logger.debug("Keep alive pool job, '{}' is '{}'", getThing().getThingTypeUID(),
getThing().getStatusInfo().getStatus());
}
}
private void setOfflineAndScheduleConnectRetry() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/message.processor.connection.error.keep-alive");
// Connection lost, avoid sending unsubscription messages
udpSenderActive = false;
disconnect();
scheduleConnectRetry(retryConnectInMinutes);
}
private void handleStatusUpdate(EmotivaUdpResponse emotivaUdpResponse) {
udpSenderActive = true;
logger.debug("Received data from '{}' with length '{}'", emotivaUdpResponse.ipAddress(),
logger.trace("Received data from '{}' with length '{}'", emotivaUdpResponse.ipAddress(),
emotivaUdpResponse.answer().length());
Object object;
@ -351,10 +383,10 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
String highlightValue = "";
for (var row = 4; row <= 6; row++) {
var emotivaMenuRow = answerDto.getRow().get(row);
EmotivaMenuRow emotivaMenuRow = answerDto.getRow().get(row);
logger.debug("Checking row '{}' with '{}' columns", row, emotivaMenuRow.getCol().size());
for (var column = 0; column <= 2; column++) {
var emotivaMenuCol = emotivaMenuRow.getCol().get(column);
EmotivaMenuCol emotivaMenuCol = emotivaMenuRow.getCol().get(column);
String cellValue = "";
if (emotivaMenuCol.getValue() != null) {
cellValue = emotivaMenuCol.getValue();
@ -371,7 +403,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
highlightValue = cellValue;
}
var channelName = format("%s-%s-%s", CHANNEL_MENU_DISPLAY_PREFIX, getMenuPanelRowLabel(row),
String channelName = format("%s-%s-%s", CHANNEL_MENU_DISPLAY_PREFIX, getMenuPanelRowLabel(row),
getMenuPanelColumnLabel(column));
updateChannelState(channelName, new StringType(cellValue));
}
@ -381,7 +413,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
private void handleMenuNotifyProgressMessage(String progressBarTimeInSeconds) {
try {
var seconds = Integer.parseInt(progressBarTimeInSeconds);
int seconds = Integer.parseInt(progressBarTimeInSeconds);
for (var count = 0; seconds >= count; count++) {
updateChannelState(CHANNEL_MENU_DISPLAY_HIGHLIGHT,
new StringType(updateProgress(EmotivaCommandHelper.integerToPercentage(count))));
@ -395,7 +427,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
logger.debug("Resetting Menu Panel Display");
for (var row = 4; row <= 6; row++) {
for (var column = 0; column <= 2; column++) {
var channelName = format("%s-%s-%s", CHANNEL_MENU_DISPLAY_PREFIX, getMenuPanelRowLabel(row),
String channelName = format("%s-%s-%s", CHANNEL_MENU_DISPLAY_PREFIX, getMenuPanelRowLabel(row),
getMenuPanelColumnLabel(column));
updateChannelState(channelName, new StringType(""));
}
@ -409,11 +441,9 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
try {
localSendingService.sendUpdate(tags, config);
} catch (InterruptedIOException e) {
logger.debug("Interrupted during sending of EmotivaUpdate message to device '{}'",
this.getThing().getThingTypeUID(), e);
logger.debug("Interrupted during sending of EmotivaUpdate message to device '{}'", thing.getUID(), e);
} catch (IOException e) {
logger.error("Failed to send EmotivaUpdate message to device '{}'", this.getThing().getThingTypeUID(),
e);
logger.error("Failed to send EmotivaUpdate message to device '{}'", thing.getUID(), e);
}
}
}
@ -440,7 +470,8 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
private void handleChannelUpdate(String emotivaSubscriptionName, String value, String visible, String status) {
logger.debug("Handling channel update for '{}' with value '{}'", emotivaSubscriptionName, value);
logger.trace("Subscription property '{}' with raw value '{}' received, start processing",
emotivaSubscriptionName, value);
if (status.equals(NOT_VALID.name())) {
logger.debug("Subscription property '{}' not present in device, skipping", emotivaSubscriptionName);
@ -448,11 +479,20 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
if ("None".equals(value)) {
logger.debug("No value present for channel {}, usually means a speaker is not enabled",
logger.debug(
"Subscription property '{}' has no value, no update needed, usually means a speaker is not enabled",
emotivaSubscriptionName);
return;
}
if (keepAlive.name().equals(emotivaSubscriptionName)) {
state.updateLastSeen(ZonedDateTime.now(ZoneId.systemDefault()).toInstant());
logger.trace(
"Subscription property '{}' with value '{}' mapped to last-seen for device '{}', value updated",
keepAlive.name(), value.trim(), thing.getUID());
return;
}
try {
EmotivaSubscriptionTags.hasChannel(emotivaSubscriptionName);
} catch (IllegalArgumentException e) {
@ -462,7 +502,8 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
if (noSubscriptionToChannel().contains(EmotivaSubscriptionTags.valueOf(emotivaSubscriptionName))) {
logger.debug("Initial subscription status update for {}, skipping, only want notifications",
logger.debug(
"Subscription property '{}' is not mapped to a OH channel, no update needed, only used for logging",
emotivaSubscriptionName);
return;
}
@ -472,35 +513,35 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
try {
subscriptionTag = EmotivaSubscriptionTags.valueOf(emotivaSubscriptionName);
} catch (IllegalArgumentException e) {
logger.debug("Property '{}' could not be mapped subscription tag, skipping", emotivaSubscriptionName);
logger.debug("Subscription property '{}' could not be mapped to Emotiva property tag, skipping",
emotivaSubscriptionName);
return;
}
if (subscriptionTag.getChannel().isEmpty()) {
logger.debug("Subscription property '{}' does not have a corresponding channel, skipping",
logger.debug("Subscription property '{}' does not have a corresponding OH channel, skipping",
emotivaSubscriptionName);
return;
}
String trimmedValue = value.trim();
logger.debug("Found subscription '{}' for '{}' and value '{}'", subscriptionTag, emotivaSubscriptionName,
trimmedValue);
logger.trace("Subscription property '{}' with value '{}' mapped to OH channel '{}'", subscriptionTag,
trimmedValue, subscriptionTag.getChannel());
// Add/Update user assigned name for inputs
if (subscriptionTag.getChannel().startsWith(CHANNEL_INPUT1.substring(0, CHANNEL_INPUT1.indexOf("-") + 1))
&& "true".equals(visible)) {
state.updateSourcesMainZone(EmotivaControlCommands.matchToInput(subscriptionTag.name()), trimmedValue);
logger.debug("Adding '{}' to dynamic source input list, map is now {}", trimmedValue,
state.getSourcesMainZone());
logger.trace("Adding/Updating '{}' to OH channel '{}' state options, all options are now {}",
trimmedValue, CHANNEL_SOURCE, state.getSourcesMainZone());
}
// Add/Update audio modes
if (subscriptionTag.getChannel().startsWith(CHANNEL_MODE + "-") && "true".equals(visible)) {
String modeName = i18nProvider.getText("channel-type.emotiva.selected-mode.option."
+ subscriptionTag.getChannel().substring(subscriptionTag.getChannel().indexOf("_") + 1));
logger.debug("Adding '{} ({})' from channel '{}' to dynamic mode list", trimmedValue, modeName,
subscriptionTag.getChannel());
logger.trace("Adding/Updating '{} ({})' from property '{}' to OH channel '{}' state options",
trimmedValue, modeName, subscriptionTag.getName(), CHANNEL_MODE);
state.updateModes(EmotivaSubscriptionTags.fromChannelUID(subscriptionTag.getChannel()), trimmedValue);
}
@ -514,15 +555,15 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
private void findChannelDatatypeAndUpdateChannel(String channelName, String value, EmotivaDataType dataType) {
switch (dataType) {
case DIMENSIONLESS_DECIBEL -> {
var trimmedString = value.replaceAll("[ +]", "");
logger.debug("Update channel '{}' to '{}:{}'", channelName, QuantityType.class.getSimpleName(),
trimmedString);
String trimmedString = value.replaceAll("[ +]", "");
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, trimmedString,
QuantityType.class.getSimpleName());
if (channelName.equals(CHANNEL_MAIN_VOLUME)) {
updateVolumeChannels(trimmedString, CHANNEL_MUTE, channelName, CHANNEL_MAIN_VOLUME_DB);
} else if (channelName.equals(CHANNEL_ZONE2_VOLUME)) {
updateVolumeChannels(trimmedString, CHANNEL_ZONE2_MUTE, channelName, CHANNEL_ZONE2_VOLUME_DB);
} else {
if (trimmedString.equals("None")) {
if ("None".equals(trimmedString)) {
updateChannelState(channelName, QuantityType.valueOf(0, Units.DECIBEL));
} else {
updateChannelState(channelName,
@ -531,13 +572,14 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
}
case DIMENSIONLESS_PERCENT -> {
var trimmedString = value.replaceAll("[ +]", "");
logger.debug("Update channel '{}' to '{}:{}'", channelName, PercentType.class.getSimpleName(), value);
String trimmedString = value.replaceAll("[ +]", "");
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
PercentType.class.getSimpleName());
updateChannelState(channelName, PercentType.valueOf(trimmedString));
}
case FREQUENCY_HERTZ -> {
logger.debug("Update channel '{}' to '{}:{}'", channelName, Units.HERTZ.getClass().getSimpleName(),
value);
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
Units.HERTZ.getClass().getSimpleName());
if (!value.isEmpty()) {
// Getting rid of characters and empty space leaves us with the raw frequency
try {
@ -557,21 +599,18 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
case GOODBYE -> {
logger.info(
"Received goodbye notification from '{}'; disconnecting and scheduling av connection retry in '{}' minutes",
getThing().getUID(), DEFAULT_RETRY_INTERVAL_MINUTES);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "@text/message.processor.goodbye");
// Device gone, sending unsubscription messages not needed
udpSenderActive = false;
disconnect();
scheduleConnectRetry(retryConnectInMinutes);
thing.getUID(), DEFAULT_RETRY_INTERVAL_MINUTES);
setOfflineAndScheduleConnectRetry();
}
case NUMBER_TIME -> {
logger.debug("Update channel '{}' to '{}:{}'", channelName, Number.class.getSimpleName(), value);
long nowEpochSecond = Instant.now().getEpochSecond();
updateChannelState(channelName, new QuantityType<>(nowEpochSecond, Units.SECOND));
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
Number.class.getSimpleName());
updateChannelState(channelName,
new QuantityType<>(ZonedDateTime.now(ZoneId.systemDefault()).toEpochSecond(), Units.SECOND));
}
case ON_OFF -> {
logger.debug("Update channel '{}' to '{}:{}'", channelName, OnOffType.class.getSimpleName(), value);
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
OnOffType.class.getSimpleName());
OnOffType switchValue = OnOffType.from(value.trim().toUpperCase());
updateChannelState(channelName, switchValue);
if (switchValue.equals(OnOffType.OFF) && CHANNEL_MENU.equals(channelName)) {
@ -579,7 +618,8 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
}
case STRING -> {
logger.debug("Update channel '{}' to '{}:{}'", channelName, StringType.class.getSimpleName(), value);
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
StringType.class.getSimpleName());
updateChannelState(channelName, StringType.valueOf(value));
}
case UNKNOWN -> // Do nothing, types not connect to channels
@ -592,7 +632,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
private void updateChannelState(String channelID, State channelState) {
state.updateChannel(channelID, channelState);
logger.trace("Updating channel '{}' with '{}'", channelID, channelState);
logger.trace("Updating OH channel '{}' with value '{}'", channelID, channelState);
updateState(channelID, channelState);
}
@ -625,29 +665,33 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
}
} else {
try {
Optional<State> channel = state.getChannel(channelUID.getId());
if (channel.isPresent()) {
EmotivaControlDTO dto = emotivaRequest.createDTO(ohCommand, channel.get());
localSendingService.send(dto);
Optional<EmotivaControlDTO> dto = state.getChannel(channelUID.getId())
.map(previousState -> emotivaRequest.createDTO(ohCommand, previousState))
.or(() -> Optional.of(emotivaRequest.createDTO(ohCommand, UnDefType.UNDEF)));
localSendingService.send(dto.get());
if (emotivaRequest.getName().equals(EmotivaControlCommands.volume.name())) {
if (ohCommand instanceof PercentType value) {
updateChannelState(CHANNEL_MAIN_VOLUME_DB, QuantityType
.valueOf(volumePercentageToDecibel(value.intValue()), Units.DECIBEL));
} else if (ohCommand instanceof QuantityType<?> value) {
updateChannelState(CHANNEL_MAIN_VOLUME, volumeDecibelToPercentage(value.toString()));
}
} else if (emotivaRequest.getName().equals(EmotivaControlCommands.zone2_volume.name())) {
if (ohCommand instanceof PercentType value) {
updateChannelState(CHANNEL_ZONE2_VOLUME_DB, QuantityType
.valueOf(volumePercentageToDecibel(value.intValue()), Units.DECIBEL));
} else if (ohCommand instanceof QuantityType<?> value) {
updateChannelState(CHANNEL_ZONE2_VOLUME, volumeDecibelToPercentage(value.toString()));
}
} else if (ohCommand instanceof OnOffType value) {
if (value.equals(OnOffType.ON) && emotivaRequest.getOnCommand().equals(power_on)) {
localSendingService.sendUpdate(EmotivaSubscriptionTags.speakerChannels(), config);
}
if (emotivaRequest.getName().equals(EmotivaControlCommands.volume.name())
|| emotivaRequest.getName().equals(EmotivaControlCommands.set_volume.name())) {
logger.debug("OhCommand '{}:{}' is of type main zone volume", channelUID.getId(), ohCommand);
if (ohCommand instanceof PercentType value) {
updateChannelState(CHANNEL_MAIN_VOLUME_DB,
QuantityType.valueOf(volumePercentageToDecibel(value.intValue()), Units.DECIBEL));
} else if (ohCommand instanceof QuantityType<?> value) {
updateChannelState(CHANNEL_MAIN_VOLUME, volumeDecibelToPercentage(value.toString()));
}
} else if (emotivaRequest.getName().equals(EmotivaControlCommands.zone2_volume.name())
|| emotivaRequest.getName().equals(EmotivaControlCommands.zone2_set_volume.name())) {
logger.debug("OhCommand '{}:{}' is of type zone 2 volume", channelUID.getId(), ohCommand);
if (ohCommand instanceof PercentType value) {
updateChannelState(CHANNEL_ZONE2_VOLUME_DB,
QuantityType.valueOf(volumePercentageToDecibel(value.intValue()), Units.DECIBEL));
} else if (ohCommand instanceof QuantityType<?> value) {
updateChannelState(CHANNEL_ZONE2_VOLUME, volumeDecibelToPercentage(value.toString()));
}
} else if (ohCommand instanceof OnOffType value) {
logger.debug("OhCommand '{}:{}' is of type switch", channelUID.getId(), ohCommand);
if (value.equals(OnOffType.ON) && emotivaRequest.getOnCommand().equals(power_on)) {
localSendingService.sendUpdate(EmotivaSubscriptionTags.speakerChannels(), config);
}
}
} catch (InterruptedIOException e) {
@ -663,7 +707,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
@Override
public void dispose() {
logger.debug("Disposing '{}'", getThing().getUID());
logger.debug("Disposing '{}'", thing.getUID());
disconnect();
super.dispose();

View File

@ -20,6 +20,7 @@ import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlComman
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.band_fm;
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.channel_1;
import java.time.Instant;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
@ -44,6 +45,7 @@ public class EmotivaProcessorState {
private EnumMap<EmotivaControlCommands, String> sourcesMainZone;
private EnumMap<EmotivaControlCommands, String> sourcesZone2;
private final EnumMap<EmotivaSubscriptionTags, String> modes;
private Instant lastSeen = Instant.EPOCH;
private EnumMap<EmotivaControlCommands, String> tunerChannels = new EnumMap<>(
Map.ofEntries(Map.entry(channel_1, channel_1.getLabel()),
@ -146,4 +148,12 @@ public class EmotivaProcessorState {
public void removeChannel(String channel) {
channelStateMap.remove(channel);
}
public void updateLastSeen(Instant instant) {
lastSeen = instant;
}
public Instant getLastSeen() {
return lastSeen;
}
}

View File

@ -73,7 +73,7 @@ public class EmotivaUdpBroadcastService {
*/
public Optional<DiscoveryResult> discoverThings() {
try {
final DatagramPacket receivePacket = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
final var receivePacket = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
// No need to call close first, because the caller of this method already has done it.
discoverSocket = new DatagramSocket(
@ -82,7 +82,7 @@ public class EmotivaUdpBroadcastService {
byte[] emotivaPingDTO = xmlUtils.marshallEmotivaDTO(new EmotivaPingDTO(PROTOCOL_V3.name()))
.getBytes(Charset.defaultCharset());
final DatagramPacket discoverPacket = new DatagramPacket(emotivaPingDTO, emotivaPingDTO.length, broadcast,
final var discoverPacket = new DatagramPacket(emotivaPingDTO, emotivaPingDTO.length, broadcast,
EmotivaBindingConstants.DEFAULT_PING_PORT);
DatagramSocket localDatagramSocket = discoverSocket;
@ -146,7 +146,7 @@ public class EmotivaUdpBroadcastService {
*/
private Optional<DiscoveryResult> thingDiscovered(DatagramPacket packet) {
final String ipAddress = packet.getAddress().getHostAddress();
String udpResponse = new String(packet.getData(), 0, packet.getLength() - 1, StandardCharsets.UTF_8);
final var udpResponse = new String(packet.getData(), 0, packet.getLength() - 1, StandardCharsets.UTF_8);
Object object;
try {
@ -159,8 +159,7 @@ public class EmotivaUdpBroadcastService {
if (object instanceof EmotivaTransponderDTO answerDto) {
logger.trace("Processing Received '{}' with '{}' ", EmotivaTransponderDTO.class.getSimpleName(),
udpResponse);
final ThingUID thingUid = new ThingUID(
THING_PROCESSOR + AbstractUID.SEPARATOR + ipAddress.replace(".", ""));
final var thingUid = new ThingUID(THING_PROCESSOR + AbstractUID.SEPARATOR + ipAddress.replace(".", ""));
final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUid)
.withThingType(THING_PROCESSOR).withProperty("ipAddress", ipAddress)
.withProperty("controlPort", answerDto.getControl().getControlPort())

View File

@ -150,7 +150,7 @@ public class EmotivaUdpReceivingService {
final DatagramSocket localReceivingSocket = receivingSocket;
while (localListener != null && localReceivingSocket != null && receivingSocket != null) {
try {
final DatagramPacket answer = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
final var answer = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
listenerNotifyActive = true;
localReceivingSocket.receive(answer); // receive packet (blocking call)
@ -193,8 +193,8 @@ public class EmotivaUdpReceivingService {
executorService.execute(() -> {
if (answer.getAddress() != null && answer.getLength() > 0) {
logger.trace("Received data on port '{}'", answer.getPort());
EmotivaUdpResponse emotivaUdpResponse = new EmotivaUdpResponse(
new String(answer.getData(), 0, answer.getLength()), answer.getAddress().getHostAddress());
var emotivaUdpResponse = new EmotivaUdpResponse(new String(answer.getData(), 0, answer.getLength()),
answer.getAddress().getHostAddress());
localListener.accept(emotivaUdpResponse);
}
});

View File

@ -128,8 +128,8 @@ public class EmotivaUdpSendingService {
executorService.execute(() -> {
if (answer.getAddress() != null && answer.getLength() > 0) {
logger.trace("Received data on port '{}'", answer.getPort());
EmotivaUdpResponse emotivaUdpResponse = new EmotivaUdpResponse(
new String(answer.getData(), 0, answer.getLength()), answer.getAddress().getHostAddress());
var emotivaUdpResponse = new EmotivaUdpResponse(new String(answer.getData(), 0, answer.getLength()),
answer.getAddress().getHostAddress());
localListener.accept(emotivaUdpResponse);
}
});
@ -183,17 +183,17 @@ public class EmotivaUdpSendingService {
final InetAddress ipAddress = InetAddress.getByName(this.ipAddress);
byte[] buf = msg.getBytes(Charset.defaultCharset());
DatagramPacket packet = new DatagramPacket(buf, buf.length, ipAddress, sendingControlPort);
var packet = new DatagramPacket(buf, buf.length, ipAddress, sendingControlPort);
// make sure we are not interrupted by a disconnect while sending this message
synchronized (this) {
DatagramSocket localDatagramSocket = this.sendingSocket;
final DatagramPacket answer = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
final var answer = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
final Consumer<EmotivaUdpResponse> localListener = listener;
if (localDatagramSocket != null && !localDatagramSocket.isClosed()) {
localDatagramSocket.setSoTimeout(DEFAULT_UDP_SENDING_TIMEOUT);
localDatagramSocket.send(packet);
logger.debug("Sending successful");
logger.trace("Successfully sending to {}:{}", ipAddress, sendingControlPort);
localDatagramSocket.receive(answer);
@ -209,4 +209,8 @@ public class EmotivaUdpSendingService {
}
}
}
public boolean isConnected() {
return sendingSocket != null;
}
}

View File

@ -82,7 +82,7 @@ public class InputStateOptionProvider extends BaseDynamicStateDescriptionProvide
for (EmotivaSubscriptionTags modeKey : modeKeys) {
options.add(new StateOption(modeKey.name(), modes.get(modeKey)));
}
logger.debug("Updated '{}' with '{}'", CHANNEL_MODE, options);
logger.trace("Updating OH channel '{}' with state options '{}'", CHANNEL_MODE, options);
setStateOptions(channel.getUID(), options);
}
}
@ -100,7 +100,7 @@ public class InputStateOptionProvider extends BaseDynamicStateDescriptionProvide
options.add(new StateOption(sourceKey.name(), sourceKey.getLabel()));
}
}
logger.debug("Updated '{}' with '{}'", channel.getUID().getId(), options);
logger.trace("Updating OH channel '{}' with state options '{}'", channel.getUID().getId(), options);
setStateOptions(channel.getUID(), options);
}
}

View File

@ -71,7 +71,7 @@ public class EmotivaCommandDTO {
* @return EmotivaCommandDTO with ack=yes always added
*/
public static EmotivaCommandDTO fromTypeWithAck(EmotivaControlCommands command) {
EmotivaCommandDTO emotivaCommandDTO = new EmotivaCommandDTO(command);
var emotivaCommandDTO = new EmotivaCommandDTO(command);
emotivaCommandDTO.setAck(DEFAULT_CONTROL_ACK_VALUE);
return emotivaCommandDTO;
}
@ -82,7 +82,7 @@ public class EmotivaCommandDTO {
* @return EmotivaCommandDTO with ack=yes always added
*/
public static EmotivaCommandDTO fromTypeWithAck(EmotivaControlCommands command, String value) {
EmotivaCommandDTO emotivaCommandDTO = new EmotivaCommandDTO(command);
var emotivaCommandDTO = new EmotivaCommandDTO(command);
if (value != null) {
emotivaCommandDTO.setValue(value);
}
@ -99,7 +99,7 @@ public class EmotivaCommandDTO {
}
public static EmotivaCommandDTO fromTypeWithAck(EmotivaSubscriptionTags command) {
EmotivaCommandDTO emotivaCommandDTO = new EmotivaCommandDTO(command);
var emotivaCommandDTO = new EmotivaCommandDTO(command);
emotivaCommandDTO.setAck(DEFAULT_CONTROL_ACK_VALUE);
return emotivaCommandDTO;
}

View File

@ -230,7 +230,7 @@ public enum EmotivaControlCommands {
EnumMap<EmotivaControlCommands, String> commands = new EnumMap<>(EmotivaControlCommands.class);
for (EmotivaControlCommands value : values()) {
if (value.getCommandType().equals(filter)) {
StringBuilder sb = new StringBuilder(value.name());
var sb = new StringBuilder(value.name());
sb.setCharAt(0, Character.toUpperCase(value.name().charAt(0)));
commands.put(value, sb.toString());
}

View File

@ -21,7 +21,6 @@ import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.FREQ
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.emotiva.internal.EmotivaProcessorState;
import org.openhab.binding.emotiva.internal.dto.EmotivaControlDTO;
import org.openhab.core.library.types.OnOffType;
@ -105,7 +104,7 @@ public class EmotivaControlRequest {
}
}
public EmotivaControlDTO createDTO(Command ohCommand, @Nullable State previousState) {
public EmotivaControlDTO createDTO(Command ohCommand, State previousState) {
switch (defaultCommand.getCommandType()) {
case CYCLE -> {
return EmotivaControlDTO.create(defaultCommand);
@ -115,9 +114,16 @@ public class EmotivaControlRequest {
try {
return EmotivaControlDTO.create(EmotivaControlCommands.valueOf(value.toString().toLowerCase()));
} catch (IllegalArgumentException e) {
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} threw exception trying to map to a valid Emotiva control command",
channel, ohCommand.getClass().getSimpleName(), MENU_CONTROL);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, is not of OH String type",
channel, ohCommand.getClass().getSimpleName(), MENU_CONTROL);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case MODE -> {
if (ohCommand instanceof StringType value) {
@ -132,6 +138,9 @@ public class EmotivaControlRequest {
} else if ("-1".equals(value.toString())) {
return EmotivaControlDTO.create(getDownCommand(), -1);
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} threw exception trying to map to a valid Emotiva control command",
channel, ohCommand.getClass().getSimpleName(), MODE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
} else if (ohCommand instanceof Number value) {
@ -141,13 +150,18 @@ public class EmotivaControlRequest {
return EmotivaControlDTO.create(getDownCommand(), -1);
}
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, is not a OH String or Number type",
channel, ohCommand.getClass().getSimpleName(), MODE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case NUMBER -> {
if (ohCommand instanceof Number value) {
return handleNumberTypes(getSetCommand(), ohCommand, value);
} else {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name,
NUMBER, ohCommand.getClass().getSimpleName());
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, not a OH Number type",
channel, ohCommand.getClass().getSimpleName(), NUMBER);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
@ -166,6 +180,9 @@ public class EmotivaControlRequest {
return matchToCommandMap(ohCommand, MAP_SOURCES_ZONE_2);
}
default -> {
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {}, is not a supported OH channel type",
channel, ohCommand.getClass().getSimpleName(), NONE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
@ -182,11 +199,27 @@ public class EmotivaControlRequest {
return EmotivaControlDTO.create(getOffCommand());
}
} else {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name, SET,
ohCommand.getClass().getSimpleName());
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command",
channel, ohCommand.getClass().getSimpleName(), SET);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
case SOURCE_MAIN_ZONE -> {
logger.debug("OH command {}:{} mapped to Emotiva Command type {} always defaults to none command",
channel, ohCommand.getClass().getSimpleName(), SOURCE_MAIN_ZONE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case SOURCE_USER -> {
logger.debug("OH command {}:{} mapped to Emotiva Command type {} always defaults to none command",
channel, ohCommand.getClass().getSimpleName(), SOURCE_USER);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case SOURCE_ZONE2 -> {
logger.debug("OH command {}:{} mapped to Emotiva Command type {} always defaults to none command",
channel, ohCommand.getClass().getSimpleName(), SOURCE_ZONE2);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case SPEAKER_PRESET -> {
if (ohCommand instanceof StringType value) {
try {
@ -207,8 +240,9 @@ public class EmotivaControlRequest {
return EmotivaControlDTO.create(getOffCommand());
}
} else {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name,
TOGGLE, ohCommand.getClass().getSimpleName());
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, not a OH OnOff type",
channel, ohCommand.getClass().getSimpleName(), TOGGLE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
@ -231,6 +265,9 @@ public class EmotivaControlRequest {
}
}
// Reached max or min value, not sending anything
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} reached max or min value, no change",
channel, ohCommand.getClass().getSimpleName(), UP_DOWN_SINGLE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
} else if (ohCommand instanceof StringType value) {
if ("1".equals(value.toString())) {
@ -244,41 +281,48 @@ public class EmotivaControlRequest {
} else {
return EmotivaControlDTO.create(getDownCommand(), -1);
}
} else {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name,
UP_DOWN_SINGLE, ohCommand.getClass().getSimpleName());
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command",
channel, ohCommand.getClass().getSimpleName(), UP_DOWN_SINGLE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
case UP_DOWN_HALF -> {
if (ohCommand instanceof Number value) {
if (value.intValue() <= maxValue || value.intValue() >= minValue) {
Number pre = (Number) previousState;
if (pre == null) {
if (value.doubleValue() > 0) {
if (ohCommand instanceof Number ohCommandDecimalType) {
if (ohCommandDecimalType.intValue() <= maxValue || ohCommandDecimalType.intValue() >= minValue) {
if (previousState instanceof Number previousStateValue) {
if (ohCommandDecimalType.doubleValue() > previousStateValue.doubleValue()) {
return EmotivaControlDTO.create(getUpCommand());
} else if (value.doubleValue() < 0) {
} else if (ohCommandDecimalType.doubleValue() < previousStateValue.doubleValue()) {
return EmotivaControlDTO.create(getDownCommand());
}
} else {
if (value.doubleValue() > pre.doubleValue()) {
if (ohCommandDecimalType.doubleValue() > 0) {
return EmotivaControlDTO.create(getUpCommand());
} else if (value.doubleValue() < pre.doubleValue()) {
} else if (ohCommandDecimalType.doubleValue() < 0) {
return EmotivaControlDTO.create(getDownCommand());
}
}
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} with value {} reached max or min value, no change",
channel, ohCommand.getClass().getSimpleName(), UP_DOWN_HALF,
ohCommandDecimalType.intValue());
return EmotivaControlDTO.create(EmotivaControlCommands.none);
} else {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name,
UP_DOWN_HALF, ohCommand.getClass().getSimpleName());
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, not a OH Number type",
channel, ohCommand.getClass().getSimpleName(), UP_DOWN_HALF);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
default -> {
logger.debug(
"OH command {}:{} has no Emotiva Command type, could not be matched to a Emotiva control command",
channel, ohCommand.getClass().getSimpleName());
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
private EmotivaControlDTO matchToCommandMap(Command ohCommand, String mapName) {
@ -293,6 +337,9 @@ public class EmotivaControlRequest {
}
}
}
logger.debug(
"OH command {}:{} mapped to Emotiva Command type {} could not be matched to a Emotiva control command, not a OH String type",
channel, ohCommand.getClass().getSimpleName(), NONE);
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
@ -331,8 +378,9 @@ public class EmotivaControlRequest {
return EmotivaControlDTO.create(getDefaultCommand(), value.intValue());
}
default -> {
logger.debug("Could not create EmotivaControlDTO for {}:{}:{}, ohCommand is {}", channel, name,
setCommand.getDataType(), ohCommand.getClass().getSimpleName());
logger.debug(
"OH command {}:{} mapped to Emotiva Command type:datatype {}:{} could not be matched to a Emotiva control command",
channel, ohCommand.getClass().getSimpleName(), NUMBER, setCommand.getDataType());
return EmotivaControlDTO.create(EmotivaControlCommands.none);
}
}

View File

@ -39,8 +39,8 @@ public enum EmotivaDataType {
}
public static EmotivaDataType fromName(String name) {
EmotivaDataType result = EmotivaDataType.UNKNOWN;
for (EmotivaDataType m : EmotivaDataType.values()) {
var result = EmotivaDataType.UNKNOWN;
for (var m : EmotivaDataType.values()) {
if (m.name.equals(name)) {
result = m;
break;

View File

@ -84,7 +84,7 @@ public enum EmotivaSubscriptionTags {
menu_update("menu-update", STRING, CHANNEL_MENU_DISPLAY_PREFIX),
/* Protocol V3 notify tags */
keepAlive("keepAlive", NUMBER_TIME, LAST_SEEN_STATE_NAME),
keepAlive("keepAlive", NUMBER_TIME, ""),
goodBye("goodBye", GOODBYE, ""),
bar_update("bar-update", STRING, CHANNEL_BAR),
width("width", DIMENSIONLESS_DECIBEL, CHANNEL_WIDTH),
@ -132,13 +132,18 @@ public enum EmotivaSubscriptionTags {
return EmotivaSubscriptionTags.unknown;
}
public static List<EmotivaSubscriptionTags> channels(String zonePrefix) {
public static List<EmotivaSubscriptionTags> channels(String prefix) {
List<EmotivaSubscriptionTags> tags = new ArrayList<>();
for (EmotivaSubscriptionTags value : values()) {
if (value.channel.startsWith(zonePrefix)) {
if (value.channel.startsWith(prefix)) {
tags.add(value);
}
}
// Always add keepAlive tag to the general prefix
if ("general".equals(prefix)) {
tags.add(EmotivaSubscriptionTags.keepAlive);
}
return tags;
}

View File

@ -28,7 +28,7 @@ public record EmotivaUdpResponse(String answer, String ipAddress) {
if (o == null || getClass() != o.getClass()) {
return false;
}
EmotivaUdpResponse that = (EmotivaUdpResponse) o;
var that = (EmotivaUdpResponse) o;
return answer.equals(that.answer) && ipAddress.equals(that.ipAddress);
}
}

View File

@ -83,7 +83,7 @@ public class EmotivaXmlUtils {
public String marshallEmotivaDTO(Object objectInstanceType) {
try {
StringWriter out = new StringWriter();
var out = new StringWriter();
marshaller.marshal(objectInstanceType, out);
return out.toString();
} catch (JAXBException e) {
@ -94,14 +94,14 @@ public class EmotivaXmlUtils {
public String marshallJAXBElementObjects(AbstractJAXBElementDTO jaxbElementDTO) {
try {
StringWriter out = new StringWriter();
var out = new StringWriter();
List<JAXBElement<String>> commandsAsJAXBElement = new ArrayList<>();
if (jaxbElementDTO.getCommands() != null) {
for (EmotivaCommandDTO command : jaxbElementDTO.getCommands()) {
if (command.getName() != null) {
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if (command.getValue() != null) {
sb.append(" value=\"").append(command.getValue()).append("\"");
}
@ -114,7 +114,7 @@ public class EmotivaXmlUtils {
if (command.getAck() != null) {
sb.append(" ack=\"").append(command.getAck()).append("\"");
}
QName name = new QName("%s%s".formatted(command.getName().trim(), sb));
var name = new QName("%s%s".formatted(command.getName().trim(), sb));
commandsAsJAXBElement.add(jaxbElementDTO.createJAXBElement(name));
}
}
@ -143,8 +143,8 @@ public class EmotivaXmlUtils {
throw new JAXBException("Could not unmarshall value, xml value is null or empty");
}
StringReader xmlAsStringReader = new StringReader(xmlAsString);
StreamSource xmlAsStringStream = new StreamSource(xmlAsStringReader);
var xmlAsStringReader = new StringReader(xmlAsString);
var xmlAsStringStream = new StreamSource(xmlAsStringReader);
object = unmarshaller.unmarshal(xmlAsStringStream);
return object;
}
@ -153,7 +153,7 @@ public class EmotivaXmlUtils {
List<EmotivaCommandDTO> commands = new ArrayList<>();
for (Object object : objects) {
try {
Element xmlElement = (Element) object;
var xmlElement = (Element) object;
try {
EmotivaCommandDTO commandDTO = getEmotivaCommandDTO(xmlElement);
@ -172,7 +172,7 @@ public class EmotivaXmlUtils {
List<EmotivaNotifyDTO> commands = new ArrayList<>();
for (Object object : objects) {
try {
Element xmlElement = (Element) object;
var xmlElement = (Element) object;
try {
EmotivaNotifyDTO tagDTO = getEmotivaNotifyTags(xmlElement);
@ -191,7 +191,7 @@ public class EmotivaXmlUtils {
List<EmotivaBarNotifyDTO> commands = new ArrayList<>();
for (Object object : objects) {
try {
Element xmlElement = (Element) object;
var xmlElement = (Element) object;
try {
EmotivaBarNotifyDTO tagDTO = getEmotivaBarNotify(xmlElement);
@ -236,7 +236,7 @@ public class EmotivaXmlUtils {
LOGGER.debug("Could not create EmotivaCommand, unknown command {}", xmlElement.getTagName());
commandType = EmotivaControlCommands.none;
}
EmotivaCommandDTO commandDTO = new EmotivaCommandDTO(commandType);
var commandDTO = new EmotivaCommandDTO(commandType);
if (xmlElement.hasAttribute("status")) {
commandDTO.setStatus(xmlElement.getAttribute("status"));
}
@ -250,7 +250,7 @@ public class EmotivaXmlUtils {
}
private static EmotivaBarNotifyDTO getEmotivaBarNotify(Element xmlElement) {
EmotivaBarNotifyDTO barNotify = new EmotivaBarNotifyDTO(xmlElement.getTagName().trim());
var barNotify = new EmotivaBarNotifyDTO(xmlElement.getTagName().trim());
if (xmlElement.hasAttribute("type")) {
barNotify.setType(xmlElement.getAttribute("type"));
}
@ -280,7 +280,7 @@ public class EmotivaXmlUtils {
LOGGER.debug("Could not create EmotivaNotify, unknown subscription tag {}", xmlElement.getTagName());
notifyTagName = UNKNOWN_TAG;
}
EmotivaNotifyDTO commandDTO = new EmotivaNotifyDTO(notifyTagName);
var commandDTO = new EmotivaNotifyDTO(notifyTagName);
if (xmlElement.hasAttribute("status")) {
commandDTO.setStatus(xmlElement.getAttribute("status"));
}

View File

@ -88,9 +88,9 @@ class EmotivaCommandHelperTest {
void testChannelToControlRequest(String channel, String name, EmotivaDataType emotivaDataType,
EmotivaControlCommands defaultCommand, EmotivaControlCommands onCommand, EmotivaControlCommands offCommand,
EmotivaControlCommands setCommand, EmotivaProtocolVersion version, double min, double max) {
EmotivaProcessorState state = new EmotivaProcessorState();
var state = new EmotivaProcessorState();
EmotivaControlRequest surround = EmotivaCommandHelper.channelToControlRequest(channel, state, version);
assertThat(surround.getName(), is(name));
assertThat(surround.getChannel(), is(channel));
assertThat(surround.getDataType(), is(emotivaDataType));

View File

@ -38,6 +38,7 @@ class EmotivaAckDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallValidCommand() throws JAXBException {
EmotivaAckDTO dto = (EmotivaAckDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaAckPowerOff);
assertThat(dto, is(notNullValue()));
assertThat(dto.getCommands().size(), is(1));
}
@ -45,8 +46,11 @@ class EmotivaAckDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallOneValidCommand() throws JAXBException {
EmotivaAckDTO dto = (EmotivaAckDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaAckPowerOffAndNotRealCommand);
assertThat(dto, is(notNullValue()));
List<EmotivaCommandDTO> commands = xmlUtils.unmarshallXmlObjectsToControlCommands(dto.getCommands());
assertThat(commands.size(), is(2));
assertThat(commands.get(0), is(notNullValue()));

View File

@ -38,10 +38,12 @@ class EmotivaBarNotifyDTOTest extends AbstractDTOTestBase {
void testUnmarshall() throws JAXBException {
EmotivaBarNotifyWrapper dto = (EmotivaBarNotifyWrapper) xmlUtils
.unmarshallToEmotivaDTO(emotivaBarNotifyBigText);
assertThat(dto.getSequence(), is("98"));
assertThat(dto.getTags().size(), is(1));
List<EmotivaBarNotifyDTO> commands = xmlUtils.unmarshallToBarNotify(dto.getTags());
assertThat(commands.get(0).getType(), is("bigText"));
assertThat(commands.get(0).getText(), is("XBox One"));
assertThat(commands.get(0).getUnits(), is(nullValue()));

View File

@ -38,6 +38,7 @@ class EmotivaCommandDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallElements() {
List<EmotivaCommandDTO> commandDTO = xmlUtils.unmarshallToCommands(emotivaCommandoPowerOn);
assertThat(commandDTO, is(notNullValue()));
assertThat(commandDTO.size(), is(1));
assertThat(commandDTO.get(0).getName(), is(EmotivaControlCommands.power_on.name()));
@ -46,6 +47,7 @@ class EmotivaCommandDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallFromEmotivaAckWithMissingEnumType() {
List<EmotivaCommandDTO> commandDTO = xmlUtils.unmarshallToCommands(emotivaAckPowerOffAndNotRealCommand);
assertThat(commandDTO, is(notNullValue()));
assertThat(commandDTO.size(), is(2));
assertThat(commandDTO.get(0).getName(), is(EmotivaControlCommands.power_off.name()));
@ -60,7 +62,8 @@ class EmotivaCommandDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallFromEmotivaAck() {
List<EmotivaCommandDTO> commandDTO = xmlUtils.unmarshallToCommands(emotivaAckPowerOffAndVolume);
var commandDTO = xmlUtils.unmarshallToCommands(emotivaAckPowerOffAndVolume);
assertThat(commandDTO, is(notNullValue()));
assertThat(commandDTO.size(), is(2));
assertThat(commandDTO.get(0).getName(), is(EmotivaControlCommands.power_off.name()));

View File

@ -38,8 +38,9 @@ class EmotivaControlDTOTest extends AbstractDTOTestBase {
@Test
void marshalWithNoCommand() {
EmotivaControlDTO control = new EmotivaControlDTO(null);
var control = new EmotivaControlDTO(null);
String xmlString = xmlUtils.marshallJAXBElementObjects(control);
assertThat(xmlString, containsString("<emotivaControl/>"));
assertThat(xmlString, not(containsString("<property")));
assertThat(xmlString, not(containsString("</emotivaControl>")));
@ -47,16 +48,18 @@ class EmotivaControlDTOTest extends AbstractDTOTestBase {
@Test
void marshalNoCommand() {
EmotivaControlDTO control = new EmotivaControlDTO(Collections.emptyList());
var control = new EmotivaControlDTO(Collections.emptyList());
String xmlString = xmlUtils.marshallJAXBElementObjects(control);
assertThat(xmlString, containsString("<emotivaControl/>"));
}
@Test
void marshalCommand() {
EmotivaCommandDTO command = EmotivaCommandDTO.fromTypeWithAck(EmotivaControlCommands.set_volume, "10");
EmotivaControlDTO control = new EmotivaControlDTO(List.of(command));
var control = new EmotivaControlDTO(List.of(command));
String xmlString = xmlUtils.marshallJAXBElementObjects(control);
assertThat(xmlString, containsString("<emotivaControl>"));
assertThat(xmlString, containsString("<set_volume value=\"10\" ack=\"yes\" />"));
assertThat(xmlString, endsWith("</emotivaControl>\n"));
@ -64,10 +67,10 @@ class EmotivaControlDTOTest extends AbstractDTOTestBase {
@Test
void marshalWithTwoCommands() {
EmotivaControlDTO control = new EmotivaControlDTO(
List.of(EmotivaCommandDTO.fromTypeWithAck(EmotivaControlCommands.power_on),
EmotivaCommandDTO.fromTypeWithAck(EmotivaControlCommands.hdmi1)));
var control = new EmotivaControlDTO(List.of(EmotivaCommandDTO.fromTypeWithAck(EmotivaControlCommands.power_on),
EmotivaCommandDTO.fromTypeWithAck(EmotivaControlCommands.hdmi1)));
String xmlString = xmlUtils.marshallJAXBElementObjects(control);
assertThat(xmlString, containsString("<emotivaControl>"));
assertThat(xmlString, containsString("<power_on ack=\"yes\" />"));
assertThat(xmlString, containsString("<hdmi1 ack=\"yes\" />"));

View File

@ -34,7 +34,8 @@ class EmotivaMenuNotifyDTOTest extends AbstractDTOTestBase {
@Test
void testUnmarshallMenu() throws JAXBException {
EmotivaMenuNotifyDTO dto = (EmotivaMenuNotifyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaMenuNotify);
var dto = (EmotivaMenuNotifyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaMenuNotify);
assertThat(dto.getProgress(), is(nullValue()));
assertThat(dto.getSequence(), is("2378"));
assertThat(dto.getRow().size(), is(11));
@ -57,7 +58,8 @@ class EmotivaMenuNotifyDTOTest extends AbstractDTOTestBase {
@Test
void testUnmarshallProgress() throws JAXBException {
EmotivaMenuNotifyDTO dto = (EmotivaMenuNotifyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaMenuNotifyProgress);
var dto = (EmotivaMenuNotifyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaMenuNotifyProgress);
assertThat(dto.getSequence(), is("2405"));
assertThat(dto.getRow(), is(nullValue()));
assertThat(dto.getProgress().getTime(), is("15"));

View File

@ -39,7 +39,7 @@ class EmotivaNotifyWrapperTest extends AbstractDTOTestBase {
@Test
void marshallWithNoProperty() {
EmotivaNotifyWrapper dto = new EmotivaNotifyWrapper(emotivaNotifyV2KeepAliveSequence, Collections.emptyList());
var dto = new EmotivaNotifyWrapper(emotivaNotifyV2KeepAliveSequence, Collections.emptyList());
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString,
containsString("<emotivaNotify sequence=\"" + emotivaNotifyV2KeepAliveSequence + "\"/>"));
@ -50,9 +50,9 @@ class EmotivaNotifyWrapperTest extends AbstractDTOTestBase {
@Test
void marshallWithOneProperty() {
List<EmotivaPropertyDTO> keepAliveProperty = List.of(new EmotivaPropertyDTO("keepAlive", "7500", "true"));
EmotivaNotifyWrapper dto = new EmotivaNotifyWrapper(emotivaNotifyV2KeepAliveSequence, keepAliveProperty);
var dto = new EmotivaNotifyWrapper(emotivaNotifyV2KeepAliveSequence, keepAliveProperty);
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
var xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString,
containsString("<emotivaNotify sequence=\"" + emotivaNotifyV2KeepAliveSequence + "\">"));
assertThat(xmlAsString, containsString("<property name=\"keepAlive\" value=\"7500\" visible=\"true\"/>"));
@ -61,11 +61,11 @@ class EmotivaNotifyWrapperTest extends AbstractDTOTestBase {
@Test
void testUnmarshallV2() throws JAXBException {
EmotivaNotifyWrapper dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV2KeepAlive);
var dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV2KeepAlive);
assertThat(dto.getSequence(), is(emotivaNotifyV2KeepAliveSequence));
assertThat(dto.getTags().size(), is(1));
assertThat(dto.getTags().get(0), instanceOf(Element.class));
Element keepAlive = (Element) dto.getTags().get(0);
var keepAlive = (Element) dto.getTags().get(0);
assertThat(keepAlive.getTagName(), is(EmotivaSubscriptionTags.keepAlive.name()));
assertThat(keepAlive.hasAttribute("value"), is(true));
assertThat(keepAlive.getAttribute("value"), is("7500"));
@ -76,18 +76,18 @@ class EmotivaNotifyWrapperTest extends AbstractDTOTestBase {
@Test
void testUnmarshallV2UnknownProperty() throws JAXBException {
EmotivaNotifyWrapper dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV2UnknownTag);
var dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV2UnknownTag);
assertThat(dto.getSequence(), is(emotivaNotifyV2KeepAliveSequence));
assertThat(dto.getTags().size(), is(1));
assertThat(dto.getTags().get(0), instanceOf(Element.class));
Element unknownCommand = (Element) dto.getTags().get(0);
var unknownCommand = (Element) dto.getTags().get(0);
assertThat(unknownCommand.getTagName(), is("unknownTag"));
assertThat(dto.getProperties(), is(nullValue()));
}
@Test
void testUnmarshallV3() throws JAXBException {
EmotivaNotifyWrapper dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV3KeepAlive);
var dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV3KeepAlive);
assertThat(dto.getSequence(), is(emotivaNotifyV2KeepAliveSequence));
assertThat(dto.getProperties().size(), is(1));
assertThat(dto.getTags(), is(nullValue()));
@ -95,8 +95,8 @@ class EmotivaNotifyWrapperTest extends AbstractDTOTestBase {
@Test
void testUnmarshallV3EmptyValue() throws JAXBException {
EmotivaNotifyWrapper dto = (EmotivaNotifyWrapper) xmlUtils
.unmarshallToEmotivaDTO(emotivaNotifyV3EmptyMenuValue);
var dto = (EmotivaNotifyWrapper) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyV3EmptyMenuValue);
assertThat(dto.getSequence(), is("23929"));
assertThat(dto.getProperties().size(), is(1));
assertThat(dto.getProperties().get(0).getName(), is("menu"));

View File

@ -34,8 +34,9 @@ class EmotivaPingDTOTest extends AbstractDTOTestBase {
@Test
void marshallPlain() {
EmotivaPingDTO dto = new EmotivaPingDTO();
var dto = new EmotivaPingDTO();
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString, containsString("<emotivaPing/>"));
assertThat(xmlAsString, not(containsString("<property")));
assertThat(xmlAsString, not(containsString("</emotivaPing>")));
@ -43,8 +44,9 @@ class EmotivaPingDTOTest extends AbstractDTOTestBase {
@Test
void marshallWithProtocol() {
EmotivaPingDTO dto = new EmotivaPingDTO("3.0");
var dto = new EmotivaPingDTO("3.0");
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString, containsString("<emotivaPing protocol=\"3.0\"/>"));
assertThat(xmlAsString, not(containsString("<property")));
assertThat(xmlAsString, not(containsString("</emotivaPing>")));
@ -52,14 +54,16 @@ class EmotivaPingDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallV2() throws JAXBException {
EmotivaPingDTO dto = (EmotivaPingDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaPingV2);
var dto = (EmotivaPingDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaPingV2);
assertThat(dto, is(notNullValue()));
assertThat(dto.getProtocol(), is(nullValue()));
}
@Test
void unmarshallV3() throws JAXBException {
EmotivaPingDTO dto = (EmotivaPingDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaPingV3);
var dto = (EmotivaPingDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaPingV3);
assertThat(dto, is(notNullValue()));
assertThat(dto.getProtocol(), is(notNullValue()));
assertThat(dto.getProtocol(), is("3.0"));

View File

@ -37,8 +37,8 @@ class EmotivaPropertyDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallFromEmotivaNotify() throws JAXBException {
EmotivaPropertyDTO commandDTO = (EmotivaPropertyDTO) xmlUtils
.unmarshallToEmotivaDTO(emotivaNotifyEmotivaPropertyPower);
var commandDTO = (EmotivaPropertyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaNotifyEmotivaPropertyPower);
assertThat(commandDTO, is(notNullValue()));
assertThat(commandDTO.getName(), is(EmotivaSubscriptionTags.tuner_channel.name()));
assertThat(commandDTO.getValue(), is("FM 106.50MHz"));
@ -48,8 +48,8 @@ class EmotivaPropertyDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallFromEmotivaUpdate() throws JAXBException {
EmotivaPropertyDTO commandDTO = (EmotivaPropertyDTO) xmlUtils
.unmarshallToEmotivaDTO(emotivaUpdateEmotivaPropertyPower);
var commandDTO = (EmotivaPropertyDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaUpdateEmotivaPropertyPower);
assertThat(commandDTO, is(notNullValue()));
assertThat(commandDTO.getName(), is(EmotivaControlCommands.power.name()));
assertThat(commandDTO.getValue(), is("On"));

View File

@ -41,8 +41,9 @@ class EmotivaSubscriptionRequestTest extends AbstractDTOTestBase {
@Test
void marshalFromChannelUID() {
EmotivaSubscriptionTags subscriptionChannel = EmotivaSubscriptionTags.fromChannelUID(CHANNEL_TUNER_RDS);
EmotivaSubscriptionRequest emotivaSubscriptionRequest = new EmotivaSubscriptionRequest(subscriptionChannel);
var emotivaSubscriptionRequest = new EmotivaSubscriptionRequest(subscriptionChannel);
String xmlString = xmlUtils.marshallJAXBElementObjects(emotivaSubscriptionRequest);
assertThat(xmlString, containsString("<emotivaSubscription protocol=\"2.0\">"));
assertThat(xmlString, containsString("<tuner_RDS ack=\"yes\" />"));
assertThat(xmlString, containsString("</emotivaSubscription>"));
@ -50,11 +51,10 @@ class EmotivaSubscriptionRequestTest extends AbstractDTOTestBase {
@Test
void marshallWithSubscriptionNoAck() {
EmotivaCommandDTO command = new EmotivaCommandDTO(EmotivaControlCommands.volume, "10", "yes");
EmotivaSubscriptionRequest dto = new EmotivaSubscriptionRequest(command, PROTOCOL_V2.value());
var command = new EmotivaCommandDTO(EmotivaControlCommands.volume, "10", "yes");
var dto = new EmotivaSubscriptionRequest(command, PROTOCOL_V2.value());
String xmlString = xmlUtils.marshallJAXBElementObjects(dto);
assertThat(xmlString, containsString("<emotivaSubscription protocol=\"2.0\">"));
assertThat(xmlString, containsString("<volume value=\"10\" ack=\"yes\" />"));
assertThat(xmlString, containsString("</emotivaSubscription>"));
@ -64,6 +64,7 @@ class EmotivaSubscriptionRequestTest extends AbstractDTOTestBase {
@Test
void unmarshall() throws JAXBException {
var dto = (EmotivaSubscriptionResponse) xmlUtils.unmarshallToEmotivaDTO(emotivaSubscriptionRequest);
assertThat(dto, is(notNullValue()));
assertThat(dto.getTags().size(), is(3));
assertThat(dto.getProperties(), is(nullValue()));

View File

@ -42,6 +42,7 @@ class EmotivaSubscriptionResponseTest extends AbstractDTOTestBase {
void marshallNoProperty() {
var dto = new EmotivaSubscriptionResponse(Collections.emptyList());
String xmlString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlString, containsString("<emotivaSubscription/>"));
assertThat(xmlString, not(containsString("</emotivaSubscription>")));
assertThat(xmlString, not(containsString("<property")));
@ -51,9 +52,10 @@ class EmotivaSubscriptionResponseTest extends AbstractDTOTestBase {
@Test
void marshallWithOneProperty() {
EmotivaPropertyDTO emotivaPropertyDTO = new EmotivaPropertyDTO(power_on.name(), "On", "true");
var emotivaPropertyDTO = new EmotivaPropertyDTO(power_on.name(), "On", "true");
var dto = new EmotivaSubscriptionResponse(Collections.singletonList(emotivaPropertyDTO));
String xmlString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlString, containsString("<emotivaSubscription>"));
assertThat(xmlString, containsString("<property name=\"power_on\" value=\"On\" visible=\"true\"/>"));
assertThat(xmlString, not(containsString("<property>")));
@ -64,9 +66,12 @@ class EmotivaSubscriptionResponseTest extends AbstractDTOTestBase {
@Test
void unmarshall() throws JAXBException {
var dto = (EmotivaSubscriptionResponse) xmlUtils.unmarshallToEmotivaDTO(emotivaSubscriptionResponse);
assertThat(dto.tags, is(notNullValue()));
assertThat(dto.tags.size(), is(5));
List<EmotivaNotifyDTO> commands = xmlUtils.unmarshallToNotification(dto.getTags());
assertThat(commands, is(notNullValue()));
assertThat(commands.size(), is(dto.tags.size()));
assertThat(commands.get(0), instanceOf(EmotivaNotifyDTO.class));

View File

@ -34,8 +34,8 @@ class EmotivaTransponderDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallV2() throws JAXBException {
EmotivaTransponderDTO dto = (EmotivaTransponderDTO) xmlUtils
.unmarshallToEmotivaDTO(emotivaTransponderResponseV2);
var dto = (EmotivaTransponderDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaTransponderResponseV2);
assertThat(dto, is(notNullValue()));
assertThat(dto.getModel(), is("XMC-1"));
assertThat(dto.getRevision(), is("2.0"));
@ -50,8 +50,8 @@ class EmotivaTransponderDTOTest extends AbstractDTOTestBase {
@Test
void unmarshallV3() throws JAXBException {
EmotivaTransponderDTO dto = (EmotivaTransponderDTO) xmlUtils
.unmarshallToEmotivaDTO(emotivaTransponderResponseV3);
var dto = (EmotivaTransponderDTO) xmlUtils.unmarshallToEmotivaDTO(emotivaTransponderResponseV3);
assertThat(dto, is(notNullValue()));
assertThat(dto.getModel(), is("XMC-2"));
assertThat(dto.getRevision(), is("3.0"));

View File

@ -37,9 +37,10 @@ class EmotivaUnsubscriptionTest extends AbstractDTOTestBase {
@Test
void marshalFromChannelUID() {
EmotivaSubscriptionTags subscriptionChannel = EmotivaSubscriptionTags.fromChannelUID(CHANNEL_TUNER_RDS);
EmotivaUnsubscribeDTO emotivaSubscriptionRequest = new EmotivaUnsubscribeDTO(subscriptionChannel);
var subscriptionChannel = EmotivaSubscriptionTags.fromChannelUID(CHANNEL_TUNER_RDS);
var emotivaSubscriptionRequest = new EmotivaUnsubscribeDTO(subscriptionChannel);
String xmlString = xmlUtils.marshallJAXBElementObjects(emotivaSubscriptionRequest);
assertThat(xmlString, containsString("<emotivaUnsubscribe>"));
assertThat(xmlString, containsString("<tuner_RDS />"));
assertThat(xmlString, containsString("</emotivaUnsubscribe>"));
@ -47,11 +48,10 @@ class EmotivaUnsubscriptionTest extends AbstractDTOTestBase {
@Test
void marshallWithTwoUnsubscriptions() {
EmotivaCommandDTO command1 = new EmotivaCommandDTO(EmotivaControlCommands.volume);
EmotivaUnsubscribeDTO dto = new EmotivaUnsubscribeDTO(command1);
var command1 = new EmotivaCommandDTO(EmotivaControlCommands.volume);
var dto = new EmotivaUnsubscribeDTO(command1);
String xmlString = xmlUtils.marshallJAXBElementObjects(dto);
assertThat(xmlString, containsString("<emotivaUnsubscribe>"));
assertThat(xmlString, containsString("<volume />"));
assertThat(xmlString, containsString("</emotivaUnsubscribe>"));

View File

@ -38,8 +38,9 @@ class EmotivaUpdateRequestTest extends AbstractDTOTestBase {
@Test
void marshallWithNoProperty() {
EmotivaUpdateRequest dto = new EmotivaUpdateRequest(Collections.emptyList());
var dto = new EmotivaUpdateRequest(Collections.emptyList());
String xmlAsString = xmlUtils.marshallJAXBElementObjects(dto);
assertThat(xmlAsString, containsString("<emotivaUpdate/>"));
assertThat(xmlAsString, not(containsString("<property")));
assertThat(xmlAsString, not(containsString("</emotivaUpdate>")));
@ -47,10 +48,10 @@ class EmotivaUpdateRequestTest extends AbstractDTOTestBase {
@Test
void marshalFromChannelUID() {
EmotivaSubscriptionTags subscriptionChannel = EmotivaSubscriptionTags
.fromChannelUID(EmotivaBindingConstants.CHANNEL_TUNER_RDS);
EmotivaUpdateRequest emotivaUpdateRequest = new EmotivaUpdateRequest(subscriptionChannel);
var subscriptionChannel = EmotivaSubscriptionTags.fromChannelUID(EmotivaBindingConstants.CHANNEL_TUNER_RDS);
var emotivaUpdateRequest = new EmotivaUpdateRequest(subscriptionChannel);
String xmlString = xmlUtils.marshallJAXBElementObjects(emotivaUpdateRequest);
assertThat(xmlString, containsString("<emotivaUpdate>"));
assertThat(xmlString, containsString("<tuner_RDS />"));
assertThat(xmlString, containsString("</emotivaUpdate>"));

View File

@ -40,8 +40,9 @@ class EmotivaUpdateResponseTest extends AbstractDTOTestBase {
@Test
void marshallWithNoProperty() {
EmotivaUpdateResponse dto = new EmotivaUpdateResponse(Collections.emptyList());
var dto = new EmotivaUpdateResponse(Collections.emptyList());
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString, containsString("<emotivaUpdate/>"));
assertThat(xmlAsString, not(containsString("<property")));
assertThat(xmlAsString, not(containsString("</emotivaUpdate>")));
@ -50,9 +51,12 @@ class EmotivaUpdateResponseTest extends AbstractDTOTestBase {
@Test
void unmarshallV2() throws JAXBException {
var dto = (EmotivaUpdateResponse) xmlUtils.unmarshallToEmotivaDTO(emotivaUpdateResponseV2);
assertThat(dto, is(notNullValue()));
assertThat(dto.getProperties(), is(nullValue()));
List<EmotivaNotifyDTO> notifications = xmlUtils.unmarshallToNotification(dto.getTags());
assertThat(notifications.size(), is(3));
assertThat(notifications.get(0).getName(), is(EmotivaSubscriptionTags.power.name()));
@ -74,6 +78,7 @@ class EmotivaUpdateResponseTest extends AbstractDTOTestBase {
@Test
void unmarshallV3() throws JAXBException {
var dto = (EmotivaUpdateResponse) xmlUtils.unmarshallToEmotivaDTO(emotivaUpdateResponseV3);
assertThat(dto, is(notNullValue()));
assertThat(dto.getTags(), is(nullValue()));
assertThat(dto.getProperties().size(), is(3));

View File

@ -19,10 +19,8 @@ import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlComman
import static org.openhab.binding.emotiva.internal.protocol.EmotivaProtocolVersion.*;
import static org.openhab.core.types.RefreshType.REFRESH;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -42,6 +40,7 @@ import org.openhab.core.library.types.UpDownType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* Unit tests for EmotivaControl requests.
@ -216,7 +215,6 @@ class EmotivaControlRequestTest {
EmotivaControlCommands.class);
private static final EnumMap<EmotivaControlCommands, String> RADIO_BAND_MAP = new EnumMap<>(
EmotivaControlCommands.class);
private static final Map<String, State> STATE_MAP = Collections.synchronizedMap(new HashMap<>());
private static final EmotivaProcessorState state = new EmotivaProcessorState();
@BeforeAll
@ -244,9 +242,9 @@ class EmotivaControlRequestTest {
RADIO_BAND_MAP.put(band_fm, "FM");
state.setTunerBands(RADIO_BAND_MAP);
STATE_MAP.put(CHANNEL_TREBLE, new DecimalType(-3));
STATE_MAP.put(CHANNEL_TUNER_CHANNEL, new StringType("FM 87.50MHz"));
STATE_MAP.put(CHANNEL_FREQUENCY, QuantityType.valueOf(107.90, Units.HERTZ));
state.updateChannel(CHANNEL_TREBLE, new DecimalType(-3));
state.updateChannel(CHANNEL_TUNER_CHANNEL, new StringType("FM 87.50MHz"));
state.updateChannel(CHANNEL_FREQUENCY, QuantityType.valueOf(107.90, Units.HERTZ));
}
@ParameterizedTest
@ -256,7 +254,8 @@ class EmotivaControlRequestTest {
EmotivaControlRequest controlRequest = EmotivaCommandHelper.channelToControlRequest(channel, state,
protocolVersion);
EmotivaControlDTO dto = controlRequest.createDTO(ohValue, STATE_MAP.get(channel));
Optional<State> previousState = state.getChannel(channel).or(() -> Optional.of(UnDefType.UNDEF));
EmotivaControlDTO dto = controlRequest.createDTO(ohValue, previousState.get());
assertThat(dto.getCommands().size(), is(1));
assertThat(dto.getCommands().get(0).getName(), is(controlCommand.name()));
assertThat(dto.getCommands().get(0).getValue(), is(requestValue));

View File

@ -62,13 +62,15 @@ class EmotivaXmlUtilsTest extends AbstractDTOTestBase {
@Test
void testMarshallObjectWithoutXmlElements() {
String commands = xmlUtils.marshallEmotivaDTO("");
assertThat(commands, is(""));
}
@Test
void testMarshallNoValueDTO() {
EmotivaNotifyWrapper dto = new EmotivaNotifyWrapper();
var dto = new EmotivaNotifyWrapper();
String xmlAsString = xmlUtils.marshallEmotivaDTO(dto);
assertThat(xmlAsString, not(containsString("<emotivaNotify>")));
assertThat(xmlAsString, containsString("<emotivaNotify/>"));
}