mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-31 05:24:24 +02:00
[emotiva] Tag group handler and bugfixes. (#18437)
* Adds tag group subscription handler to reduce load on processor devices. * Fixes matching of input label to Emotiva source command. * Fixes cleaning of source input to work via REST calls. * Fixes updating of custom user labels on binding startup. * Fixes issue with missing event publisher in EmotivaInputStateOptionProvider. Signed-off-by: Espen Fossen <espenaf@junta.no>
This commit is contained in:
@@ -18,17 +18,28 @@ The binding automatically discovers devices on your network.
|
||||
The Emotiva Processor thing requires the `ipAddress` it can connect to.
|
||||
There are more parameters which all have defaults set.
|
||||
|
||||
| Parameter | Values | Default |
|
||||
|-----------------------|---------------------------------------------------------------|---------|
|
||||
| ipAddress | IP address of the processor | - |
|
||||
| controlPort | port number, e.g. 7002 | 7002 |
|
||||
| notifyPort | port number, e.g. 7003 | 7003 |
|
||||
| infoPort | port number, e.g. 7004 | 7004 |
|
||||
| setupPortTCP | port number, e.g. 7100 | 7100 |
|
||||
| menuNotifyPort | port number, e.g. 7005 | 7005 |
|
||||
| protocolVersion | Emotiva Network Protocol version, e.g. 3.0 | 2.0 |
|
||||
| keepAlive | Time between notification update from device, in milliseconds | 7500 |
|
||||
| retryConnectInMinutes | Time between connection retry, in minutes | 2 |
|
||||
| Parameter | Values | Default |
|
||||
|------------------------|---------------------------------------------------------------|---------|
|
||||
| ipAddress | IP address of the processor | - |
|
||||
| controlPort | port number, e.g. 7002 | 7002 |
|
||||
| notifyPort | port number, e.g. 7003 | 7003 |
|
||||
| infoPort | port number, e.g. 7004 | 7004 |
|
||||
| setupPortTCP | port number, e.g. 7100 | 7100 |
|
||||
| menuNotifyPort | port number, e.g. 7005 | 7005 |
|
||||
| activateFrontBar | Activates Front Bar channels | false |
|
||||
| activateOSDMenu | Activates OSD menu channels | false |
|
||||
| activateZone2 | Activates Zone 2 channels | false |
|
||||
| protocolVersion | Emotiva Network Protocol version, e.g. 3.0 | 2.0 |
|
||||
| keepAlive | Time between notification update from device, in milliseconds | 7500 |
|
||||
| retryConnectInMinutes | Time between connection retry, in minutes | 2 |
|
||||
|
||||
### Dynamic channels and extended functionality
|
||||
|
||||
Emotiva processors have limited processing power, so if the binding subscribes to all channels simultaneously the
|
||||
device might grind to a halt after a while, requiring a manual reboot of the device. The binding is designed to
|
||||
dynamically enable and disabled channels based on the selected source. Furthermore, the configuration values
|
||||
**activateFrontBar**, **activateOSDMenu** and **activateZone2** controls extra functionality this is default off to
|
||||
reduce the overall load on the device.
|
||||
|
||||
## Channels
|
||||
|
||||
|
||||
+11
@@ -47,6 +47,12 @@ public class EmotivaBindingConstants {
|
||||
/** Connection retry interval in minutes */
|
||||
static final int DEFAULT_RETRY_INTERVAL_MINUTES = 2;
|
||||
|
||||
/** Refresh source labels interval in minutes */
|
||||
static final int DEFAULT_REFRESH_SOURCE_LABEL_JOB_IN_MINUTES = 60;
|
||||
|
||||
/** Refresh source labels unsubscribe delay, giving enough time to get answer from device */
|
||||
static final int DEFAULT_REFRESH_SOURCE_UNSUBSCRIBE_DELAY_IN_SECONDS = 60;
|
||||
|
||||
/**
|
||||
* Default Emotiva device keep alive in milliseconds. {@link org.openhab.binding.emotiva.internal.dto.ControlDTO}
|
||||
*/
|
||||
@@ -94,6 +100,11 @@ public class EmotivaBindingConstants {
|
||||
static final String MENU_PANEL_HIGHLIGHTED = "true";
|
||||
static final String EMOTIVA_SOURCE_COMMAND_PREFIX = "source_";
|
||||
|
||||
/** Emotiva Configuration Constants **/
|
||||
public static final String CONFIG_ACTIVATE_FRONT_BAR = "activateFrontBar";
|
||||
public static final String CONFIG_ACTIVATE_OSD_MENU = "activateOSDMenu";
|
||||
public static final String CONFIG_ACTIVATE_ZONE2 = "activateZone2";
|
||||
|
||||
/** Emotiva Protocol V1 channels **/
|
||||
public static final String CHANNEL_STANDBY = "general#standby";
|
||||
public static final String CHANNEL_MAIN_ZONE_POWER = "main-zone#power";
|
||||
|
||||
+3
@@ -30,6 +30,9 @@ public class EmotivaConfiguration {
|
||||
public int infoPort = 7004;
|
||||
public int setupPortTCP = 7100;
|
||||
public int menuNotifyPort = 7005;
|
||||
public boolean activateFrontBar = false;
|
||||
public boolean activateOSDMenu = false;
|
||||
public boolean activateZone2 = false;
|
||||
public String protocolVersion = DEFAULT_EMOTIVA_PROTOCOL_VERSION;
|
||||
public int keepAlive = DEFAULT_KEEP_ALIVE_IN_MILLISECONDS;
|
||||
public int retryConnectInMinutes = DEFAULT_RETRY_INTERVAL_MINUTES;
|
||||
|
||||
+34
-14
@@ -28,13 +28,20 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -44,13 +51,24 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Espen Fossen - Adapted to Emotiva binding
|
||||
*/
|
||||
@Component(service = { DynamicStateDescriptionProvider.class, EmotivaInputStateOptionProvider.class })
|
||||
@NonNullByDefault
|
||||
public class InputStateOptionProvider extends BaseDynamicStateDescriptionProvider implements ThingHandlerService {
|
||||
public class EmotivaInputStateOptionProvider extends BaseDynamicStateDescriptionProvider
|
||||
implements ThingHandlerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(InputStateOptionProvider.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(EmotivaInputStateOptionProvider.class);
|
||||
|
||||
private @Nullable EmotivaProcessorHandler handler;
|
||||
|
||||
@Activate
|
||||
public EmotivaInputStateOptionProvider(final @Reference EventPublisher eventPublisher,
|
||||
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry,
|
||||
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
|
||||
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(ThingHandler handler) {
|
||||
this.handler = (EmotivaProcessorHandler) handler;
|
||||
@@ -73,9 +91,9 @@ public class InputStateOptionProvider extends BaseDynamicStateDescriptionProvide
|
||||
EmotivaProcessorHandler localHandler = handler;
|
||||
if (localHandler != null) {
|
||||
if (channel.getUID().getId().equals(CHANNEL_SOURCE)) {
|
||||
setStateOptionsForSource(channel, options, localHandler.getSourcesMainZone());
|
||||
options.addAll(gatherStateOptionsForSource(channel, localHandler.getSourcesMainZone()));
|
||||
} else if (channel.getUID().getId().equals(CHANNEL_ZONE2_SOURCE)) {
|
||||
setStateOptionsForSource(channel, options, localHandler.getSourcesZone2());
|
||||
options.addAll(gatherStateOptionsForSource(channel, localHandler.getSourcesZone2()));
|
||||
} else if (channel.getUID().getId().equals(CHANNEL_MODE)) {
|
||||
EnumMap<EmotivaSubscriptionTags, String> modes = localHandler.getModes();
|
||||
Collection<EmotivaSubscriptionTags> modeKeys = modes.keySet();
|
||||
@@ -83,24 +101,26 @@ public class InputStateOptionProvider extends BaseDynamicStateDescriptionProvide
|
||||
options.add(new StateOption(modeKey.name(), modes.get(modeKey)));
|
||||
}
|
||||
logger.trace("Updating OH channel '{}' with state options '{}'", CHANNEL_MODE, options);
|
||||
setStateOptions(channel.getUID(), options);
|
||||
}
|
||||
setStateOptions(channel.getUID(), options);
|
||||
}
|
||||
|
||||
return super.getStateDescription(channel, original, locale);
|
||||
}
|
||||
|
||||
private void setStateOptionsForSource(Channel channel, List<StateOption> options,
|
||||
EnumMap<EmotivaControlCommands, String> sources) {
|
||||
Collection<EmotivaControlCommands> sourceKeys = sources.keySet();
|
||||
for (EmotivaControlCommands sourceKey : sourceKeys) {
|
||||
if (sourceKey.name().startsWith(EMOTIVA_SOURCE_COMMAND_PREFIX)) {
|
||||
options.add(new StateOption(sourceKey.name(), sources.get(sourceKey)));
|
||||
List<StateOption> gatherStateOptionsForSource(Channel channel,
|
||||
EnumMap<EmotivaControlCommands, String> sourcesWithUserLabels) {
|
||||
List<StateOption> options = new ArrayList<>();
|
||||
Collection<EmotivaControlCommands> sourceCommands = sourcesWithUserLabels.keySet();
|
||||
for (EmotivaControlCommands command : sourceCommands) {
|
||||
// If command name starts with prefix "source_", add the user provided label, else use default label from
|
||||
// command.
|
||||
if (command.name().startsWith(EMOTIVA_SOURCE_COMMAND_PREFIX)) {
|
||||
options.add(new StateOption(command.name(), sourcesWithUserLabels.get(command)));
|
||||
} else {
|
||||
options.add(new StateOption(sourceKey.name(), sourceKey.getLabel()));
|
||||
options.add(new StateOption(command.name(), command.getLabel()));
|
||||
}
|
||||
}
|
||||
logger.trace("Updating OH channel '{}' with state options '{}'", channel.getUID().getId(), options);
|
||||
setStateOptions(channel.getUID(), options);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
+190
-34
@@ -25,8 +25,8 @@ 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.EmotivaSubscriptionTagGroup.SOURCES;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags.keepAlive;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags.noSubscriptionToChannel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
@@ -39,11 +39,15 @@ import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.quantity.Frequency;
|
||||
import javax.xml.bind.JAXBException;
|
||||
@@ -67,6 +71,7 @@ import org.openhab.binding.emotiva.internal.protocol.EmotivaCommandType;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlRequest;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaDataType;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaUdpResponse;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaXmlUtils;
|
||||
@@ -112,10 +117,12 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
private final List<EmotivaSubscriptionTags> zone2Subscriptions = EmotivaSubscriptionTags.channels("zone2");
|
||||
|
||||
private final EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
private final EmotivaSubscriptionTagGroupHandler subscriptionHandler;
|
||||
private final EmotivaTranslationProvider i18nProvider;
|
||||
|
||||
private @Nullable ScheduledFuture<?> pollingJob;
|
||||
private @Nullable ScheduledFuture<?> connectRetryJob;
|
||||
private @Nullable ScheduledFuture<?> sourceLabelRefreshJob;
|
||||
private @Nullable EmotivaUdpSendingService sendingService;
|
||||
private @Nullable EmotivaUdpReceivingService notifyListener;
|
||||
private @Nullable EmotivaUdpReceivingService menuNotifyListener;
|
||||
@@ -135,6 +142,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
super(thing);
|
||||
this.i18nProvider = i18nProvider;
|
||||
this.config = getConfigAs(EmotivaConfiguration.class);
|
||||
this.subscriptionHandler = new EmotivaSubscriptionTagGroupHandler(config, state);
|
||||
this.retryConnectInMinutes = config.retryConnectInMinutes;
|
||||
}
|
||||
|
||||
@@ -180,9 +188,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
for (int attempt = 1; attempt <= DEFAULT_CONNECTION_RETRIES && !udpSenderActive; attempt++) {
|
||||
try {
|
||||
logger.debug("Connection attempt '{}'", attempt);
|
||||
sendConnector.sendSubscription(generalSubscription, config);
|
||||
sendConnector.sendSubscription(mainZoneSubscriptions, config);
|
||||
sendConnector.sendSubscription(zone2Subscriptions, config);
|
||||
sendConnector.sendSubscription(subscriptionHandler.init(), config);
|
||||
} catch (IOException e) {
|
||||
// network or socket failure, also wait 2 sec and try again
|
||||
}
|
||||
@@ -195,6 +201,8 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
if (udpSenderActive) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
state.updateLastSeen(ZonedDateTime.now(ZoneId.systemDefault()).toInstant());
|
||||
setInitialSourceLabels();
|
||||
starthSourceLabelsRefresJob();
|
||||
startPollingKeepAlive();
|
||||
|
||||
final var menuListenerConnector = new EmotivaUdpReceivingService(localConfig.menuNotifyPort,
|
||||
@@ -220,7 +228,10 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
|
||||
private void scheduleConnectRetry(long waitMinutes) {
|
||||
logger.debug("Scheduling connection retry in '{}' minutes", waitMinutes);
|
||||
connectRetryJob = scheduler.schedule(this::connect, waitMinutes, TimeUnit.MINUTES);
|
||||
final ScheduledFuture<?> localScheduleConnectRetryJob = connectRetryJob;
|
||||
if (localScheduleConnectRetryJob == null || localScheduleConnectRetryJob.isCancelled()) {
|
||||
connectRetryJob = scheduler.schedule(this::connect, waitMinutes, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,6 +256,82 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a polling job for refreshing source labels
|
||||
*/
|
||||
private void starthSourceLabelsRefresJob() {
|
||||
final ScheduledFuture<?> localSourceLabelRefreshJob = sourceLabelRefreshJob;
|
||||
if (localSourceLabelRefreshJob == null || localSourceLabelRefreshJob.isCancelled()) {
|
||||
sourceLabelRefreshJob = scheduler.scheduleWithFixedDelay(this::refreshSourceLabels, 0,
|
||||
DEFAULT_REFRESH_SOURCE_LABEL_JOB_IN_MINUTES, TimeUnit.MINUTES);
|
||||
logger.debug("Started scheduled job to update source labels now and every {}min",
|
||||
DEFAULT_REFRESH_SOURCE_LABEL_JOB_IN_MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshSourceLabels() {
|
||||
EmotivaUdpSendingService localSendingService = sendingService;
|
||||
if (localSendingService != null) {
|
||||
try {
|
||||
localSendingService
|
||||
.sendSubscription(EmotivaSubscriptionTags.getBySubscriptionTagGroups(Set.of(SOURCES)), config);
|
||||
scheduler.schedule(this::unsubscribeSourceLabels, DEFAULT_REFRESH_SOURCE_UNSUBSCRIBE_DELAY_IN_SECONDS,
|
||||
TimeUnit.SECONDS);
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.debug("Interrupted during sending of EmotivaSubscription message to device '{}'", thing.getUID(),
|
||||
e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send EmotivaSubscription message to device '{}'", thing.getUID(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unsubscribeSourceLabels() {
|
||||
EmotivaUdpSendingService localSendingService = sendingService;
|
||||
if (localSendingService != null) {
|
||||
try {
|
||||
localSendingService
|
||||
.sendUnsubscribe(EmotivaSubscriptionTags.getBySubscriptionTagGroups(Set.of(SOURCES)));
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.debug("Interrupted during sending of EmotivaUnsubscribe message to device '{}'", thing.getUID(),
|
||||
e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send EmotivaUnsubscribe message to device '{}'", thing.getUID(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void subscribeTagGroups(Set<EmotivaSubscriptionTagGroup> groups) {
|
||||
EmotivaUdpSendingService localSendingService = sendingService;
|
||||
if (localSendingService != null) {
|
||||
try {
|
||||
localSendingService.sendSubscription(EmotivaSubscriptionTags.getBySubscriptionTagGroups(groups),
|
||||
config);
|
||||
state.updateSubscribedTagGroups(groups);
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.debug("Interrupted during sending of EmotivaSubscription message to device '{}'", thing.getUID(),
|
||||
e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send EmotivaSubscription message to device '{}'", thing.getUID(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unsubscribeTagGroups(Set<EmotivaSubscriptionTagGroup> groups) {
|
||||
EmotivaUdpSendingService localSendingService = sendingService;
|
||||
if (localSendingService != null) {
|
||||
try {
|
||||
localSendingService.sendUnsubscribe(EmotivaSubscriptionTags.getBySubscriptionTagGroups(groups));
|
||||
state.updateUnsubscribedTagGroups(groups);
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.debug("Interrupted during sending of EmotivaUnsubscribe message to device '{}'", thing.getUID(),
|
||||
e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send EmotivaUnsubscribe message to device '{}'", thing.getUID(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkKeepAliveTimestamp() {
|
||||
Instant lastKeepAliveTimestamp = state.getLastSeen();
|
||||
|
||||
@@ -355,17 +442,6 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
} else if (object instanceof EmotivaSubscriptionResponse answerDto) {
|
||||
logger.trace("Processing received '{}' with '{}'", EmotivaSubscriptionResponse.class.getSimpleName(),
|
||||
emotivaUdpResponse.answer());
|
||||
// Populates static input sources, except input
|
||||
EnumMap<EmotivaControlCommands, String> sourceMainZone = EmotivaControlCommands
|
||||
.getCommandsFromType(EmotivaCommandType.SOURCE_MAIN_ZONE);
|
||||
sourceMainZone.remove(EmotivaControlCommands.input);
|
||||
state.setSourcesMainZone(sourceMainZone);
|
||||
|
||||
EnumMap<EmotivaControlCommands, String> sourcesZone2 = EmotivaControlCommands
|
||||
.getCommandsFromType(EmotivaCommandType.SOURCE_ZONE2);
|
||||
sourcesZone2.remove(EmotivaControlCommands.input);
|
||||
state.setSourcesZone2(sourcesZone2);
|
||||
|
||||
if (answerDto.getProperties() == null) {
|
||||
for (EmotivaNotifyDTO dto : xmlUtils.unmarshallToNotification(answerDto.getTags())) {
|
||||
handleChannelUpdate(dto.getName(), dto.getValue(), dto.getVisible(), dto.getAck());
|
||||
@@ -379,6 +455,21 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets initial source labels based on command list.
|
||||
*/
|
||||
private void setInitialSourceLabels() {
|
||||
EnumMap<EmotivaControlCommands, String> sourceMainZone = EmotivaControlCommands
|
||||
.getByCommandType(EmotivaCommandType.SOURCE_MAIN_ZONE);
|
||||
sourceMainZone.remove(EmotivaControlCommands.input);
|
||||
state.setSourcesMainZone(sourceMainZone);
|
||||
|
||||
EnumMap<EmotivaControlCommands, String> sourcesZone2 = EmotivaControlCommands
|
||||
.getByCommandType(EmotivaCommandType.SOURCE_ZONE2);
|
||||
sourcesZone2.remove(EmotivaControlCommands.input);
|
||||
state.setSourcesZone2(sourcesZone2);
|
||||
}
|
||||
|
||||
private void handleMenuNotify(EmotivaMenuNotifyDTO answerDto) {
|
||||
String highlightValue = "";
|
||||
|
||||
@@ -469,16 +560,16 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleChannelUpdate(String emotivaSubscriptionName, String value, String visible, String status) {
|
||||
private void handleChannelUpdate(String emotivaSubscriptionName, String rawValue, String visible, String status) {
|
||||
logger.trace("Subscription property '{}' with raw value '{}' received, start processing",
|
||||
emotivaSubscriptionName, value);
|
||||
emotivaSubscriptionName, rawValue);
|
||||
|
||||
if (status.equals(NOT_VALID.name())) {
|
||||
logger.debug("Subscription property '{}' not present in device, skipping", emotivaSubscriptionName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("None".equals(value)) {
|
||||
if ("None".equals(rawValue)) {
|
||||
logger.debug(
|
||||
"Subscription property '{}' has no value, no update needed, usually means a speaker is not enabled",
|
||||
emotivaSubscriptionName);
|
||||
@@ -489,7 +580,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
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());
|
||||
keepAlive.name(), rawValue, thing.getUID());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -501,13 +592,6 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (noSubscriptionToChannel().contains(EmotivaSubscriptionTags.valueOf(emotivaSubscriptionName))) {
|
||||
logger.debug(
|
||||
"Subscription property '{}' is not mapped to a OH channel, no update needed, only used for logging",
|
||||
emotivaSubscriptionName);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
EmotivaSubscriptionTags subscriptionTag;
|
||||
try {
|
||||
@@ -519,19 +603,20 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
if (subscriptionTag.getChannel().isEmpty()) {
|
||||
logger.debug("Subscription property '{}' does not have a corresponding OH channel, skipping",
|
||||
emotivaSubscriptionName);
|
||||
logger.debug(
|
||||
"Subscription property '{}' with value '{}' does not have a corresponding OH channel, skipping",
|
||||
emotivaSubscriptionName, rawValue);
|
||||
return;
|
||||
}
|
||||
|
||||
String trimmedValue = value.trim();
|
||||
String trimmedValue = rawValue.trim();
|
||||
logger.trace("Subscription property '{}' with value '{}' mapped to OH channel '{}'", subscriptionTag,
|
||||
trimmedValue, subscriptionTag.getChannel());
|
||||
|
||||
// Add/Update user assigned name for inputs
|
||||
// Add/Update user assigned name for sources
|
||||
if (subscriptionTag.getChannel().startsWith(CHANNEL_INPUT1.substring(0, CHANNEL_INPUT1.indexOf("-") + 1))
|
||||
&& "true".equals(visible)) {
|
||||
state.updateSourcesMainZone(EmotivaControlCommands.matchToInput(subscriptionTag.name()), trimmedValue);
|
||||
state.updateSourcesMainZone(EmotivaControlCommands.matchFromSourceInput(subscriptionTag), trimmedValue);
|
||||
logger.trace("Adding/Updating '{}' to OH channel '{}' state options, all options are now {}",
|
||||
trimmedValue, CHANNEL_SOURCE, state.getSourcesMainZone());
|
||||
}
|
||||
@@ -621,6 +706,21 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
logger.debug("Preparing to update OH channel '{}' with value:type '{}:{}'", channelName, value,
|
||||
StringType.class.getSimpleName());
|
||||
updateChannelState(channelName, StringType.valueOf(value));
|
||||
if (channelName.equals(CHANNEL_SOURCE)) {
|
||||
EmotivaControlCommands matchedSource = matchCommandFromSourceAndLabels(value);
|
||||
if (matchedSource.equals(none)) {
|
||||
logger.error(
|
||||
"Error trying to get source command from OhCommand '{}:{}', not able to update subscriptions",
|
||||
channelName, value);
|
||||
} else {
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups = (
|
||||
subscribeSet, unsubscribeSet) -> {
|
||||
updateTagGroupChangesForSource(subscribeSet, unsubscribeSet, value, matchedSource);
|
||||
};
|
||||
subscriptionHandler.tagGroupsFromSource(matchedSource, tagGroups);
|
||||
logger.debug("Currently subscribed tag groups: '{}'", state.getSubscriptionsTagGroups());
|
||||
}
|
||||
}
|
||||
}
|
||||
case UNKNOWN -> // Do nothing, types not connect to channels
|
||||
logger.debug("Channel '{}' with UNKNOWN type and value '{}' was not updated", channelName, value);
|
||||
@@ -630,6 +730,43 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates tags subscriptions by the binding based on a source command and tag groups. The subscribe and unsubscribe
|
||||
* sets are matched against the currently subscribed tag groups to reduce number of needed subscription calls and
|
||||
* avoid recursive updates.
|
||||
*
|
||||
* @param subscribeSet Tag groups to subscribe to
|
||||
* @param unsubscribeSet Tag groups to unsubscribe from
|
||||
* @param value Input value from channel er device
|
||||
* @param matchedSource Source command matched from input value
|
||||
*/
|
||||
private void updateTagGroupChangesForSource(Set<EmotivaSubscriptionTagGroup> subscribeSet,
|
||||
Set<EmotivaSubscriptionTagGroup> unsubscribeSet, String value, EmotivaControlCommands matchedSource) {
|
||||
Set<EmotivaSubscriptionTagGroup> currentSubscriptionTagGroups = state.getSubscriptionsTagGroups();
|
||||
var unsubscribe = unsubscribeSet.stream().filter(currentSubscriptionTagGroups::contains)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
if (!unsubscribe.isEmpty()) {
|
||||
unsubscribeTagGroups(unsubscribeSet);
|
||||
}
|
||||
var subscribe = subscribeSet.stream().filter(group -> !currentSubscriptionTagGroups.contains(group))
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
if (!subscribe.isEmpty()) {
|
||||
subscribeTagGroups(subscribe);
|
||||
}
|
||||
logger.debug("Input '{}' matched to source '{}' subscribing to '{}' and unsubscribing from '{}'", value,
|
||||
matchedSource.name(), subscribe, unsubscribe);
|
||||
}
|
||||
|
||||
public EmotivaControlCommands matchCommandFromSourceAndLabels(String value) {
|
||||
Map<EmotivaControlCommands, String> map = state.getCommandMap(MAP_SOURCES_MAIN_ZONE);
|
||||
EmotivaControlCommands command = EmotivaControlCommands.matchFromSourceInput(value, map);
|
||||
if (command.equals(none)) {
|
||||
logger.debug("Could not match OH command {} with value '{}' to values in map '{}', no matching command",
|
||||
CHANNEL_SOURCE, value, map);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
private void updateChannelState(String channelID, State channelState) {
|
||||
state.updateChannel(channelID, channelState);
|
||||
logger.trace("Updating OH channel '{}' with value '{}'", channelID, channelState);
|
||||
@@ -670,7 +807,26 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
.or(() -> Optional.of(emotivaRequest.createDTO(ohCommand, UnDefType.UNDEF)));
|
||||
localSendingService.send(dto.get());
|
||||
|
||||
if (emotivaRequest.getName().equals(EmotivaControlCommands.volume.name())
|
||||
if (emotivaRequest.getDefaultCommand().equals(EmotivaControlCommands.input)
|
||||
&& ohCommand instanceof StringType sourceString) {
|
||||
try {
|
||||
EmotivaControlCommands source = EmotivaControlCommands.valueOf(sourceString.toString());
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups = (
|
||||
subscribeSet, unsubscribeSet) -> {
|
||||
logger.debug(
|
||||
"OhCommand '{}:{}' is a source command with subscribeSet '{}' and unsubscribeSet '{}'",
|
||||
channelUID.getId(), ohCommand, subscribeSet, unsubscribeSet);
|
||||
updateTagGroupChangesForSource(subscribeSet, unsubscribeSet, sourceString.toString(),
|
||||
source);
|
||||
};
|
||||
subscriptionHandler.tagGroupsFromSource(source, tagGroups);
|
||||
logger.debug("Currently subscribed tag groups: '{}'", state.getSubscriptionsTagGroups());
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error(
|
||||
"Error trying to get source command from OhCommand '{}:{}', not able to update subscriptions",
|
||||
channelUID.getId(), ohCommand);
|
||||
}
|
||||
} else 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) {
|
||||
@@ -776,7 +932,7 @@ public class EmotivaProcessorHandler extends BaseThingHandler {
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Set.of(InputStateOptionProvider.class);
|
||||
return Set.of(EmotivaInputStateOptionProvider.class);
|
||||
}
|
||||
|
||||
public EnumMap<EmotivaControlCommands, String> getSourcesMainZone() {
|
||||
|
||||
+18
-2
@@ -24,11 +24,14 @@ import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
@@ -44,6 +47,7 @@ public class EmotivaProcessorState {
|
||||
|
||||
private EnumMap<EmotivaControlCommands, String> sourcesMainZone;
|
||||
private EnumMap<EmotivaControlCommands, String> sourcesZone2;
|
||||
private final Set<EmotivaSubscriptionTagGroup> subscriptions = new HashSet<>();
|
||||
private final EnumMap<EmotivaSubscriptionTags, String> modes;
|
||||
private Instant lastSeen = Instant.EPOCH;
|
||||
|
||||
@@ -137,8 +141,8 @@ public class EmotivaProcessorState {
|
||||
channelStateMap.put(channel, state);
|
||||
}
|
||||
|
||||
public void updateSourcesMainZone(EmotivaControlCommands command, String value) {
|
||||
sourcesMainZone.put(command, value);
|
||||
public void updateSourcesMainZone(EmotivaControlCommands command, String label) {
|
||||
sourcesMainZone.put(command, label.trim());
|
||||
}
|
||||
|
||||
public void updateModes(EmotivaSubscriptionTags tag, String value) {
|
||||
@@ -156,4 +160,16 @@ public class EmotivaProcessorState {
|
||||
public Instant getLastSeen() {
|
||||
return lastSeen;
|
||||
}
|
||||
|
||||
public Set<EmotivaSubscriptionTagGroup> getSubscriptionsTagGroups() {
|
||||
return subscriptions;
|
||||
}
|
||||
|
||||
public void updateSubscribedTagGroups(Set<EmotivaSubscriptionTagGroup> toAddSubscriptions) {
|
||||
subscriptions.addAll(toAddSubscriptions);
|
||||
}
|
||||
|
||||
public void updateUnsubscribedTagGroups(Set<EmotivaSubscriptionTagGroup> toRemoveSubscriptions) {
|
||||
subscriptions.removeAll(toRemoveSubscriptions);
|
||||
}
|
||||
}
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal;
|
||||
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup.UI_DEVICE;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handles subscription tags against av given Emotiva device. Devices have limited processing power, so the device do
|
||||
* not expect an integration to subscribe to all possible tags at the same time. Tags are divided into groups that
|
||||
* correspond with source/input the device is using or configuration values set in the binding.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EmotivaSubscriptionTagGroupHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EmotivaSubscriptionTagGroupHandler.class);
|
||||
|
||||
private final EmotivaConfiguration config;
|
||||
private final EmotivaProcessorState state;
|
||||
private final List<EmotivaSubscriptionTagGroup> basicSubscriptions = List.of(EmotivaSubscriptionTagGroup.GENERAL,
|
||||
EmotivaSubscriptionTagGroup.AUDIO_ADJUSTMENT);
|
||||
|
||||
public EmotivaSubscriptionTagGroupHandler(EmotivaConfiguration config, EmotivaProcessorState state) {
|
||||
this.config = config;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public List<EmotivaSubscriptionTags> init() {
|
||||
Set<EmotivaSubscriptionTagGroup> unsubscribe = new HashSet<>();
|
||||
Set<EmotivaSubscriptionTagGroup> subscribe = new HashSet<>(basicSubscriptions);
|
||||
|
||||
if (config.activateFrontBar) {
|
||||
subscribe.add(UI_DEVICE);
|
||||
} else {
|
||||
unsubscribe.add(UI_DEVICE);
|
||||
}
|
||||
if (config.activateOSDMenu) {
|
||||
subscribe.add(EmotivaSubscriptionTagGroup.UI_MENU);
|
||||
} else {
|
||||
unsubscribe.add(EmotivaSubscriptionTagGroup.UI_MENU);
|
||||
}
|
||||
if (config.activateZone2) {
|
||||
subscribe.add(EmotivaSubscriptionTagGroup.ZONE2_GENERAL);
|
||||
} else {
|
||||
unsubscribe.add(EmotivaSubscriptionTagGroup.ZONE2_GENERAL);
|
||||
}
|
||||
|
||||
state.updateUnsubscribedTagGroups(unsubscribe);
|
||||
state.updateSubscribedTagGroups(subscribe);
|
||||
Set<EmotivaSubscriptionTagGroup> tagGroups = state.getSubscriptionsTagGroups();
|
||||
List<EmotivaSubscriptionTags> tags = EmotivaSubscriptionTags.getBySubscriptionTagGroups(tagGroups);
|
||||
logger.trace("Subscribing to tag groups '{}' and tags '{}' on binding startup.", tagGroups, tags);
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a BiConsumer with subscribe and unsubscribe tag groups based on provided source.
|
||||
*
|
||||
* @param source Provided source.
|
||||
* @param tagGroups Consumer for subscribe and unsubscribe tag groups.
|
||||
*/
|
||||
public void tagGroupsFromSource(EmotivaControlCommands source,
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups) {
|
||||
Set<EmotivaSubscriptionTagGroup> unsubscribeSet = new HashSet<>();
|
||||
Set<EmotivaSubscriptionTagGroup> subscribeSet = new HashSet<>();
|
||||
|
||||
switch (source) {
|
||||
case analog1, analog2, analog3, analog4, analog5, analog71, ARC, coax1, coax2, coax3, coax4, front_in,
|
||||
optical1, optical2, optical3, optical4, usb_stream -> {
|
||||
subscribeSet.add(EmotivaSubscriptionTagGroup.AUDIO_INFO);
|
||||
unsubscribeSet.add(EmotivaSubscriptionTagGroup.TUNER);
|
||||
unsubscribeSet.add(EmotivaSubscriptionTagGroup.VIDEO_INFO);
|
||||
}
|
||||
case hdmi1, hdmi2, hdmi3, hdmi4, hdmi5, hdmi6, hdmi7, hdmi8, source_1, source_2, source_3, source_4,
|
||||
source_5, source_6, source_7, source_8 -> {
|
||||
subscribeSet.add(EmotivaSubscriptionTagGroup.AUDIO_INFO);
|
||||
subscribeSet.add(EmotivaSubscriptionTagGroup.VIDEO_INFO);
|
||||
unsubscribeSet.add(EmotivaSubscriptionTagGroup.TUNER);
|
||||
}
|
||||
case tuner -> {
|
||||
subscribeSet.add(EmotivaSubscriptionTagGroup.TUNER);
|
||||
subscribeSet.add(EmotivaSubscriptionTagGroup.AUDIO_INFO);
|
||||
unsubscribeSet.add(EmotivaSubscriptionTagGroup.VIDEO_INFO);
|
||||
}
|
||||
default -> subscribeSet.add(EmotivaSubscriptionTagGroup.VIDEO_INFO);
|
||||
}
|
||||
tagGroups.accept(subscribeSet, unsubscribeSet);
|
||||
}
|
||||
}
|
||||
+61
-12
@@ -33,6 +33,7 @@ import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.STRI
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.UNKNOWN;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
@@ -202,18 +203,62 @@ public enum EmotivaControlCommands {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
public static EmotivaControlCommands matchToInput(String inputName) {
|
||||
for (EmotivaControlCommands value : values()) {
|
||||
if (inputName.toLowerCase().equals(value.name())) {
|
||||
return value;
|
||||
/**
|
||||
* Matches given tag to Emotiva command using the following rules:
|
||||
*
|
||||
* 1. Check if tag name matches any known {@link EmotivaControlCommands} command.
|
||||
* 2. Check if tag name has a corresponding {@link EmotivaControlCommands} source command (input_ -> source_).
|
||||
*
|
||||
* @param tag Input tag
|
||||
* @return Command matched from tag or else {@link EmotivaControlCommands#none}
|
||||
*/
|
||||
public static EmotivaControlCommands matchFromSourceInput(EmotivaSubscriptionTags tag) {
|
||||
for (EmotivaControlCommands command : values()) {
|
||||
if (tag.name().equalsIgnoreCase(command.name())) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
if (inputName.startsWith("input_")) {
|
||||
return valueOf(inputName.replace("input_", "source_"));
|
||||
if (tag.name().toLowerCase().startsWith("input_")) {
|
||||
return valueOf(tag.name().toLowerCase().replace("input_", "source_"));
|
||||
}
|
||||
return none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a string input to a {@link EmotivaControlCommands} source command, uses the rules listed below for
|
||||
* matching. User customised labels might have equal content for multiple sources, so it is up to the user to keep
|
||||
* each unique, if not the first in the set is returned.
|
||||
*
|
||||
* 1. First match between of input label and label from map.
|
||||
* 2. Check if input matches name of any command in map.
|
||||
* 3. Check if input matches name of any known {@link EmotivaControlCommands}.
|
||||
*
|
||||
* @param input Label or command input
|
||||
* @param sourceCommandToLabelMap Source to label map
|
||||
* @return Command matched from input or else {@link EmotivaControlCommands#none}
|
||||
*/
|
||||
public static EmotivaControlCommands matchFromSourceInput(String input,
|
||||
Map<EmotivaControlCommands, String> sourceCommandToLabelMap) {
|
||||
// Cleanup input, Emotiva labels might have spaces and REST API might add line breaks
|
||||
String inputTrimmed = input.trim().replaceAll("(\r\n|\n)", "");
|
||||
|
||||
for (EmotivaControlCommands command : sourceCommandToLabelMap.keySet()) {
|
||||
String label = sourceCommandToLabelMap.get(command);
|
||||
if (label != null && label.equals(inputTrimmed)) {
|
||||
return command;
|
||||
} else if (command.name().equalsIgnoreCase(inputTrimmed)) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
for (EmotivaControlCommands command : values()) {
|
||||
// Check if input label matches label of the current command list
|
||||
if (inputTrimmed.equalsIgnoreCase(command.name())) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return EmotivaControlCommands.none;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
@@ -226,13 +271,17 @@ public enum EmotivaControlCommands {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public static EnumMap<EmotivaControlCommands, String> getCommandsFromType(EmotivaCommandType filter) {
|
||||
/**
|
||||
* Provides map of Emotiva command to label for given {@link EmotivaCommandType}.
|
||||
*
|
||||
* @param filter Filter provided for reducing the map to a given type
|
||||
* @return Map
|
||||
*/
|
||||
public static EnumMap<EmotivaControlCommands, String> getByCommandType(EmotivaCommandType filter) {
|
||||
EnumMap<EmotivaControlCommands, String> commands = new EnumMap<>(EmotivaControlCommands.class);
|
||||
for (EmotivaControlCommands value : values()) {
|
||||
if (value.getCommandType().equals(filter)) {
|
||||
var sb = new StringBuilder(value.name());
|
||||
sb.setCharAt(0, Character.toUpperCase(value.name().charAt(0)));
|
||||
commands.put(value, sb.toString());
|
||||
for (EmotivaControlCommands command : values()) {
|
||||
if (command.getCommandType().equals(filter)) {
|
||||
commands.put(command, command.label);
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
|
||||
+17
-21
@@ -16,10 +16,9 @@ import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.*;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaCommandHelper.clamp;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaCommandHelper.volumePercentageToDecibel;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaCommandType.*;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.none;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.FREQUENCY_HERTZ;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.emotiva.internal.EmotivaProcessorState;
|
||||
import org.openhab.binding.emotiva.internal.dto.EmotivaControlDTO;
|
||||
@@ -168,16 +167,16 @@ public class EmotivaControlRequest {
|
||||
case NONE -> {
|
||||
switch (channel) {
|
||||
case CHANNEL_TUNER_BAND -> {
|
||||
return matchToCommandMap(ohCommand, MAP_TUNER_BANDS);
|
||||
return getDTOFromCommandInMap(ohCommand, MAP_TUNER_BANDS);
|
||||
}
|
||||
case CHANNEL_TUNER_CHANNEL_SELECT -> {
|
||||
return matchToCommandMap(ohCommand, MAP_TUNER_CHANNELS);
|
||||
return getDTOFromCommandInMap(ohCommand, MAP_TUNER_CHANNELS);
|
||||
}
|
||||
case CHANNEL_SOURCE -> {
|
||||
return matchToCommandMap(ohCommand, MAP_SOURCES_MAIN_ZONE);
|
||||
return getDTOFromCommandInMap(ohCommand, MAP_SOURCES_MAIN_ZONE);
|
||||
}
|
||||
case CHANNEL_ZONE2_SOURCE -> {
|
||||
return matchToCommandMap(ohCommand, MAP_SOURCES_ZONE_2);
|
||||
return getDTOFromCommandInMap(ohCommand, MAP_SOURCES_ZONE_2);
|
||||
}
|
||||
default -> {
|
||||
logger.debug(
|
||||
@@ -325,21 +324,19 @@ public class EmotivaControlRequest {
|
||||
}
|
||||
}
|
||||
|
||||
private EmotivaControlDTO matchToCommandMap(Command ohCommand, String mapName) {
|
||||
if (ohCommand instanceof StringType value) {
|
||||
Map<EmotivaControlCommands, String> commandMap = state.getCommandMap(mapName);
|
||||
for (EmotivaControlCommands command : commandMap.keySet()) {
|
||||
String map = commandMap.get(command);
|
||||
if (map != null && map.equals(value.toString())) {
|
||||
return EmotivaControlDTO.create(EmotivaControlCommands.matchToInput(command.toString()));
|
||||
} else if (command.name().equalsIgnoreCase(value.toString())) {
|
||||
return EmotivaControlDTO.create(command);
|
||||
}
|
||||
public EmotivaControlDTO getDTOFromCommandInMap(Command ohCommand, String mapName) {
|
||||
if (ohCommand instanceof StringType ohCommandValue) {
|
||||
EmotivaControlCommands command = EmotivaControlCommands.matchFromSourceInput(ohCommandValue.toString(),
|
||||
state.getCommandMap(mapName));
|
||||
if (command.equals(none)) {
|
||||
logger.debug("Could not match OH command {}:{} with value '{}' to '{}' map, no matching command",
|
||||
channel, ohCommand.getClass().getSimpleName(), ohCommand.toFullString(), mapName);
|
||||
}
|
||||
return EmotivaControlDTO.create(command);
|
||||
} else {
|
||||
logger.debug("Could not match OH command {}:{} with value '{}' to '{}' map , not a OH StringType", channel,
|
||||
ohCommand.getClass().getSimpleName(), ohCommand.toFullString(), mapName);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -514,7 +511,6 @@ public class EmotivaControlRequest {
|
||||
return "EmotivaControlRequest{" + "name='" + name + '\'' + ", dataType=" + dataType + ", channel='" + channel
|
||||
+ '\'' + ", defaultCommand=" + defaultCommand + ", setCommand=" + setCommand + ", onCommand="
|
||||
+ onCommand + ", offCommand=" + offCommand + ", upCommand=" + upCommand + ", downCommand=" + downCommand
|
||||
+ ", maxValue=" + maxValue + ", minValue=" + minValue + ", state=" + state + ", protocolVersion="
|
||||
+ protocolVersion + '}';
|
||||
+ ", maxValue=" + maxValue + ", minValue=" + minValue + ", protocolVersion=" + protocolVersion + '}';
|
||||
}
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal.protocol;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Emotiva subscription tag group. Each Emotiva subscription tag is assigned to group in
|
||||
* {@link EmotivaSubscriptionTags} for the possibility of handling via
|
||||
* {@link org.openhab.binding.emotiva.internal.EmotivaSubscriptionTagGroupHandler}.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum EmotivaSubscriptionTagGroup {
|
||||
AUDIO_ADJUSTMENT,
|
||||
AUDIO_INFO,
|
||||
GENERAL,
|
||||
SOURCES,
|
||||
TUNER,
|
||||
UI_DEVICE,
|
||||
UI_MENU,
|
||||
VIDEO_INFO,
|
||||
NONE,
|
||||
ZONE2_GENERAL
|
||||
}
|
||||
+73
-60
@@ -14,9 +14,11 @@ package org.openhab.binding.emotiva.internal.protocol;
|
||||
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.*;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaDataType.*;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
@@ -31,70 +33,70 @@ import org.slf4j.LoggerFactory;
|
||||
public enum EmotivaSubscriptionTags {
|
||||
|
||||
/* Protocol V1 notify tags */
|
||||
power("power", ON_OFF, CHANNEL_MAIN_ZONE_POWER),
|
||||
source("source", STRING, CHANNEL_SOURCE),
|
||||
dim("dim", DIMENSIONLESS_PERCENT, CHANNEL_DIM),
|
||||
mode("mode", STRING, CHANNEL_MODE),
|
||||
speaker_preset("speaker-preset", STRING, CHANNEL_SPEAKER_PRESET),
|
||||
center("center", DIMENSIONLESS_DECIBEL, CHANNEL_CENTER),
|
||||
subwoofer("subwoofer", DIMENSIONLESS_DECIBEL, CHANNEL_SUBWOOFER),
|
||||
surround("surround", DIMENSIONLESS_DECIBEL, CHANNEL_SURROUND),
|
||||
back("back", DIMENSIONLESS_DECIBEL, CHANNEL_BACK),
|
||||
volume("volume", DIMENSIONLESS_DECIBEL, CHANNEL_MAIN_VOLUME),
|
||||
loudness("loudness", ON_OFF, CHANNEL_LOUDNESS),
|
||||
treble("treble", DIMENSIONLESS_DECIBEL, CHANNEL_TREBLE),
|
||||
bass("bass", DIMENSIONLESS_DECIBEL, CHANNEL_BASS),
|
||||
zone2_power("zone2-power", ON_OFF, CHANNEL_ZONE2_POWER),
|
||||
zone2_volume("zone2-volume", DIMENSIONLESS_DECIBEL, CHANNEL_ZONE2_VOLUME),
|
||||
zone2_input("zone2-input", STRING, CHANNEL_ZONE2_SOURCE),
|
||||
tuner_band("tuner-band", STRING, CHANNEL_TUNER_BAND),
|
||||
tuner_channel("tuner-channel", FREQUENCY_HERTZ, CHANNEL_TUNER_CHANNEL),
|
||||
tuner_signal("tuner-signal", STRING, CHANNEL_TUNER_SIGNAL),
|
||||
tuner_program("tuner-program", STRING, CHANNEL_TUNER_PROGRAM),
|
||||
tuner_RDS("tuner-RDS", STRING, CHANNEL_TUNER_RDS),
|
||||
audio_input("audio-input", STRING, CHANNEL_AUDIO_INPUT),
|
||||
audio_bitstream("audio-bitstream", STRING, CHANNEL_AUDIO_BITSTREAM),
|
||||
audio_bits("audio-bits", STRING, CHANNEL_AUDIO_BITS),
|
||||
video_input("video-input", STRING, CHANNEL_VIDEO_INPUT),
|
||||
video_format("video-format", STRING, CHANNEL_VIDEO_FORMAT),
|
||||
video_space("video-space", STRING, CHANNEL_VIDEO_SPACE),
|
||||
input_1("input-1", STRING, CHANNEL_INPUT1),
|
||||
input_2("input-2", STRING, CHANNEL_INPUT2),
|
||||
input_3("input-3", STRING, CHANNEL_INPUT3),
|
||||
input_4("input-4", STRING, CHANNEL_INPUT4),
|
||||
input_5("input-5", STRING, CHANNEL_INPUT5),
|
||||
input_6("input-6", STRING, CHANNEL_INPUT6),
|
||||
input_7("input-7", STRING, CHANNEL_INPUT7),
|
||||
input_8("input-8", STRING, CHANNEL_INPUT8),
|
||||
power("power", ON_OFF, CHANNEL_MAIN_ZONE_POWER, GENERAL),
|
||||
source("source", STRING, CHANNEL_SOURCE, GENERAL),
|
||||
dim("dim", DIMENSIONLESS_PERCENT, CHANNEL_DIM, UI_DEVICE),
|
||||
mode("mode", STRING, CHANNEL_MODE, GENERAL),
|
||||
speaker_preset("speaker-preset", STRING, CHANNEL_SPEAKER_PRESET, AUDIO_ADJUSTMENT),
|
||||
center("center", DIMENSIONLESS_DECIBEL, CHANNEL_CENTER, AUDIO_ADJUSTMENT),
|
||||
subwoofer("subwoofer", DIMENSIONLESS_DECIBEL, CHANNEL_SUBWOOFER, AUDIO_ADJUSTMENT),
|
||||
surround("surround", DIMENSIONLESS_DECIBEL, CHANNEL_SURROUND, AUDIO_ADJUSTMENT),
|
||||
back("back", DIMENSIONLESS_DECIBEL, CHANNEL_BACK, AUDIO_ADJUSTMENT),
|
||||
volume("volume", DIMENSIONLESS_DECIBEL, CHANNEL_MAIN_VOLUME, GENERAL),
|
||||
loudness("loudness", ON_OFF, CHANNEL_LOUDNESS, AUDIO_ADJUSTMENT),
|
||||
treble("treble", DIMENSIONLESS_DECIBEL, CHANNEL_TREBLE, AUDIO_ADJUSTMENT),
|
||||
bass("bass", DIMENSIONLESS_DECIBEL, CHANNEL_BASS, AUDIO_ADJUSTMENT),
|
||||
zone2_power("zone2-power", ON_OFF, CHANNEL_ZONE2_POWER, ZONE2_GENERAL),
|
||||
zone2_volume("zone2-volume", DIMENSIONLESS_DECIBEL, CHANNEL_ZONE2_VOLUME, ZONE2_GENERAL),
|
||||
zone2_input("zone2-input", STRING, CHANNEL_ZONE2_SOURCE, ZONE2_GENERAL),
|
||||
tuner_band("tuner-band", STRING, CHANNEL_TUNER_BAND, TUNER),
|
||||
tuner_channel("tuner-channel", FREQUENCY_HERTZ, CHANNEL_TUNER_CHANNEL, TUNER),
|
||||
tuner_signal("tuner-signal", STRING, CHANNEL_TUNER_SIGNAL, TUNER),
|
||||
tuner_program("tuner-program", STRING, CHANNEL_TUNER_PROGRAM, TUNER),
|
||||
tuner_RDS("tuner-RDS", STRING, CHANNEL_TUNER_RDS, TUNER),
|
||||
audio_input("audio-input", STRING, CHANNEL_AUDIO_INPUT, AUDIO_INFO),
|
||||
audio_bitstream("audio-bitstream", STRING, CHANNEL_AUDIO_BITSTREAM, AUDIO_INFO),
|
||||
audio_bits("audio-bits", STRING, CHANNEL_AUDIO_BITS, AUDIO_INFO),
|
||||
video_input("video-input", STRING, CHANNEL_VIDEO_INPUT, VIDEO_INFO),
|
||||
video_format("video-format", STRING, CHANNEL_VIDEO_FORMAT, VIDEO_INFO),
|
||||
video_space("video-space", STRING, CHANNEL_VIDEO_SPACE, VIDEO_INFO),
|
||||
input_1("input-1", STRING, CHANNEL_INPUT1, SOURCES),
|
||||
input_2("input-2", STRING, CHANNEL_INPUT2, SOURCES),
|
||||
input_3("input-3", STRING, CHANNEL_INPUT3, SOURCES),
|
||||
input_4("input-4", STRING, CHANNEL_INPUT4, SOURCES),
|
||||
input_5("input-5", STRING, CHANNEL_INPUT5, SOURCES),
|
||||
input_6("input-6", STRING, CHANNEL_INPUT6, SOURCES),
|
||||
input_7("input-7", STRING, CHANNEL_INPUT7, SOURCES),
|
||||
input_8("input-8", STRING, CHANNEL_INPUT8, SOURCES),
|
||||
|
||||
/* Protocol V2 notify tags */
|
||||
selected_mode("selected-mode", STRING, CHANNEL_SELECTED_MODE),
|
||||
selected_movie_music("selected-movie-music", STRING, CHANNEL_SELECTED_MOVIE_MUSIC),
|
||||
mode_ref_stereo("mode-ref-stereo", STRING, CHANNEL_MODE_REF_STEREO),
|
||||
mode_stereo("mode-stereo", STRING, CHANNEL_MODE_STEREO),
|
||||
mode_music("mode-music", STRING, CHANNEL_MODE_MUSIC),
|
||||
mode_movie("mode-movie", STRING, CHANNEL_MODE_MOVIE),
|
||||
mode_direct("mode-direct", STRING, CHANNEL_MODE_DIRECT),
|
||||
mode_dolby("mode-dolby", STRING, CHANNEL_MODE_DOLBY),
|
||||
mode_dts("mode-dts", STRING, CHANNEL_MODE_DTS),
|
||||
mode_all_stereo("mode-all-stereo", STRING, CHANNEL_MODE_ALL_STEREO),
|
||||
mode_auto("mode-auto", STRING, CHANNEL_MODE_AUTO),
|
||||
mode_surround("mode-surround", STRING, CHANNEL_MODE_SURROUND),
|
||||
menu("menu", ON_OFF, CHANNEL_MENU),
|
||||
menu_update("menu-update", STRING, CHANNEL_MENU_DISPLAY_PREFIX),
|
||||
selected_mode("selected-mode", STRING, CHANNEL_SELECTED_MODE, GENERAL),
|
||||
selected_movie_music("selected-movie-music", STRING, CHANNEL_SELECTED_MOVIE_MUSIC, GENERAL),
|
||||
mode_ref_stereo("mode-ref-stereo", STRING, CHANNEL_MODE_REF_STEREO, SOURCES),
|
||||
mode_stereo("mode-stereo", STRING, CHANNEL_MODE_STEREO, SOURCES),
|
||||
mode_music("mode-music", STRING, CHANNEL_MODE_MUSIC, SOURCES),
|
||||
mode_movie("mode-movie", STRING, CHANNEL_MODE_MOVIE, SOURCES),
|
||||
mode_direct("mode-direct", STRING, CHANNEL_MODE_DIRECT, SOURCES),
|
||||
mode_dolby("mode-dolby", STRING, CHANNEL_MODE_DOLBY, SOURCES),
|
||||
mode_dts("mode-dts", STRING, CHANNEL_MODE_DTS, SOURCES),
|
||||
mode_all_stereo("mode-all-stereo", STRING, CHANNEL_MODE_ALL_STEREO, SOURCES),
|
||||
mode_auto("mode-auto", STRING, CHANNEL_MODE_AUTO, SOURCES),
|
||||
mode_surround("mode-surround", STRING, CHANNEL_MODE_SURROUND, SOURCES),
|
||||
menu("menu", ON_OFF, CHANNEL_MENU, UI_MENU),
|
||||
menu_update("menu-update", STRING, CHANNEL_MENU_DISPLAY_PREFIX, UI_MENU),
|
||||
|
||||
/* Protocol V3 notify tags */
|
||||
keepAlive("keepAlive", NUMBER_TIME, ""),
|
||||
goodBye("goodBye", GOODBYE, ""),
|
||||
bar_update("bar-update", STRING, CHANNEL_BAR),
|
||||
width("width", DIMENSIONLESS_DECIBEL, CHANNEL_WIDTH),
|
||||
height("height", DIMENSIONLESS_DECIBEL, CHANNEL_HEIGHT),
|
||||
keepAlive("keepAlive", NUMBER_TIME, "", GENERAL),
|
||||
goodBye("goodBye", GOODBYE, "", GENERAL),
|
||||
bar_update("bar-update", STRING, CHANNEL_BAR, UI_DEVICE),
|
||||
width("width", DIMENSIONLESS_DECIBEL, CHANNEL_WIDTH, AUDIO_ADJUSTMENT),
|
||||
height("height", DIMENSIONLESS_DECIBEL, CHANNEL_HEIGHT, AUDIO_ADJUSTMENT),
|
||||
|
||||
/* Notify tag not in the documentation */
|
||||
source_tuner("source-tuner", ON_OFF, ""),
|
||||
source_tuner("source-tuner", ON_OFF, "", SOURCES),
|
||||
|
||||
/* No match tag */
|
||||
unknown("unknown", UNKNOWN, "");
|
||||
unknown("unknown", UNKNOWN, "", EmotivaSubscriptionTagGroup.NONE);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EmotivaSubscriptionTags.class);
|
||||
|
||||
@@ -104,11 +106,14 @@ public enum EmotivaSubscriptionTags {
|
||||
private final String name;
|
||||
private final EmotivaDataType dataType;
|
||||
private final String channel;
|
||||
private final EmotivaSubscriptionTagGroup subscriptionTagGroup;
|
||||
|
||||
EmotivaSubscriptionTags(String name, EmotivaDataType dataType, String channel) {
|
||||
EmotivaSubscriptionTags(String name, EmotivaDataType dataType, String channel,
|
||||
EmotivaSubscriptionTagGroup subscriptionTagGroup) {
|
||||
this.name = name;
|
||||
this.dataType = dataType;
|
||||
this.channel = channel;
|
||||
this.subscriptionTagGroup = subscriptionTagGroup;
|
||||
}
|
||||
|
||||
public static boolean hasChannel(String name) {
|
||||
@@ -157,8 +162,16 @@ public enum EmotivaSubscriptionTags {
|
||||
return tags.toArray(new EmotivaSubscriptionTags[0]);
|
||||
}
|
||||
|
||||
public static List<EmotivaSubscriptionTags> noSubscriptionToChannel() {
|
||||
return List.of(goodBye);
|
||||
public static List<EmotivaSubscriptionTags> getBySubscriptionTagGroups(Set<EmotivaSubscriptionTagGroup> groups) {
|
||||
List<EmotivaSubscriptionTags> tags = new ArrayList<>();
|
||||
for (EmotivaSubscriptionTagGroup group : groups) {
|
||||
for (EmotivaSubscriptionTags value : values()) {
|
||||
if (value.subscriptionTagGroup.equals(group)) {
|
||||
tags.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -167,7 +180,7 @@ public enum EmotivaSubscriptionTags {
|
||||
|
||||
public String getEmotivaName() {
|
||||
String retVal = name.replaceAll("-", "_");
|
||||
logger.debug("Converting OH channel '{}' to Emotiva command '{}'", name, retVal);
|
||||
logger.trace("Converting OH channel '{}' to Emotiva command '{}'", name, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,27 @@
|
||||
<default>7100</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="activateFrontBar" type="boolean" required="false">
|
||||
<context>feature</context>
|
||||
<label>Enable Front Bar Channels</label>
|
||||
<description>Subscribe to notification related to front bar</description>
|
||||
<default>false</default>
|
||||
<advanced>false</advanced>
|
||||
</parameter>
|
||||
<parameter name="activateOSDMenu" type="boolean" required="false">
|
||||
<context>feature</context>
|
||||
<label>Enable Menu Channels</label>
|
||||
<description>Subscribe to notification related to OSD menu</description>
|
||||
<default>false</default>
|
||||
<advanced>false</advanced>
|
||||
</parameter>
|
||||
<parameter name="activateZone2" type="boolean" required="false">
|
||||
<context>feature</context>
|
||||
<label>Enable Zone 2 Channels</label>
|
||||
<description>Subscribe to notification related to zone 2</description>
|
||||
<default>false</default>
|
||||
<advanced>false</advanced>
|
||||
</parameter>
|
||||
<parameter name="protocolVersion" type="text" required="false">
|
||||
<context>protocol-revision</context>
|
||||
<label>Protocol Version</label>
|
||||
|
||||
@@ -22,6 +22,12 @@ thing-type.config.emotiva.config.infoPort.label = Info Port
|
||||
thing-type.config.emotiva.config.infoPort.description = UDP port
|
||||
thing-type.config.emotiva.config.setupPortTCP.label = Setup TCP Port
|
||||
thing-type.config.emotiva.config.setupPortTCP.description = TCP port for remote setup
|
||||
thing-type.config.emotiva.config.activateFrontBar.label = Front Bar Notifications
|
||||
thing-type.config.emotiva.config.activateFrontBar.description = Activate notification for front bar channel
|
||||
thing-type.config.emotiva.config.activateOSDMenu.label = OSD Menu Notifications
|
||||
thing-type.config.emotiva.config.activateOSDMenu.description = Activate notification for menu channel
|
||||
thing-type.config.emotiva.config.activateZone2.label = Zone 2 Notifications
|
||||
thing-type.config.emotiva.config.activateZone2.description = Activate notification for Zone 2 channels
|
||||
thing-type.config.emotiva.config.menuNotifyPort.label = Menu Notify Port
|
||||
thing-type.config.emotiva.config.menuNotifyPort.description = UDP port to receive menu notifications from the device
|
||||
thing-type.config.emotiva.config.protocolVersion.label = Emotiva Protocol Version
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.BINDING_ID;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.THING_PROCESSOR;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.coax1;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.hdmi1;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.source_1;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.source_2;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTags.source;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelGroupUID;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EmotivaInputStateOptionProvider}.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class EmotivaInputStateOptionProviderTest {
|
||||
|
||||
@Test
|
||||
void initialMainZoneSourcesToStateOptionsWithCustomLabels() {
|
||||
EnumMap<EmotivaControlCommands, String> mainZoneSourcesMap = new EnumMap<>(EmotivaControlCommands.class);
|
||||
mainZoneSourcesMap.put(source_1, "Input 1");
|
||||
mainZoneSourcesMap.put(source_2, "SHIELD");
|
||||
mainZoneSourcesMap.put(hdmi1, "HDMI 1");
|
||||
mainZoneSourcesMap.put(coax1, "Coax 1");
|
||||
EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
state.setSourcesMainZone(mainZoneSourcesMap);
|
||||
|
||||
EmotivaInputStateOptionProvider provider = new EmotivaInputStateOptionProvider(mock(EventPublisher.class),
|
||||
mock(ItemChannelLinkRegistry.class), mock(ChannelTypeI18nLocalizationService.class));
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_PROCESSOR, "XMC-2");
|
||||
ChannelUID channelUID = new ChannelUID(new ChannelGroupUID(thingUID, "main-zone"), source.name());
|
||||
Channel channel = ChannelBuilder.create(channelUID).withType(new ChannelTypeUID(BINDING_ID, source.name()))
|
||||
.build();
|
||||
|
||||
List<StateOption> stateOptions = provider.gatherStateOptionsForSource(channel, mainZoneSourcesMap);
|
||||
assertThat(stateOptions, not(nullValue()));
|
||||
assertThat(stateOptions.size(), is(4));
|
||||
assertThat(stateOptions.get(0).getValue(), is(source_1.name()));
|
||||
assertThat(stateOptions.get(0).getLabel(), is("Input 1"));
|
||||
assertThat(stateOptions.get(1).getValue(), is(source_2.name()));
|
||||
assertThat(stateOptions.get(1).getLabel(), is("SHIELD")); // Overridden by user
|
||||
assertThat(stateOptions.get(2).getValue(), is(hdmi1.name()));
|
||||
assertThat(stateOptions.get(2).getLabel(), is("HDMI 1"));
|
||||
assertThat(stateOptions.get(3).getValue(), is(coax1.name()));
|
||||
assertThat(stateOptions.get(3).getLabel(), is("Coax 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updatedMaineZoneSourcesToStateOptionsWithCustomLabels() {
|
||||
EnumMap<EmotivaControlCommands, String> mainZoneSourcesMap = new EnumMap<>(EmotivaControlCommands.class);
|
||||
mainZoneSourcesMap.put(source_1, "Input 1");
|
||||
mainZoneSourcesMap.put(source_2, "SHIELD");
|
||||
mainZoneSourcesMap.put(hdmi1, "HDMI 1");
|
||||
mainZoneSourcesMap.put(coax1, "Coax 1");
|
||||
EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
state.setSourcesMainZone(mainZoneSourcesMap);
|
||||
|
||||
EmotivaInputStateOptionProvider provider = new EmotivaInputStateOptionProvider(mock(EventPublisher.class),
|
||||
mock(ItemChannelLinkRegistry.class), mock(ChannelTypeI18nLocalizationService.class));
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_PROCESSOR, "XMC-2");
|
||||
ChannelUID channelUID = new ChannelUID(new ChannelGroupUID(thingUID, "main-zone"), source.name());
|
||||
Channel channel = ChannelBuilder.create(channelUID).withType(new ChannelTypeUID(BINDING_ID, source.name()))
|
||||
.build();
|
||||
|
||||
String sourceOneLabel = "Should be added to options";
|
||||
state.updateSourcesMainZone(EmotivaControlCommands.source_1, sourceOneLabel);
|
||||
state.updateSourcesMainZone(EmotivaControlCommands.hdmi1, "Should not be added to options");
|
||||
List<StateOption> stateOptions = provider.gatherStateOptionsForSource(channel, mainZoneSourcesMap);
|
||||
|
||||
assertThat(stateOptions, not(nullValue()));
|
||||
assertThat(stateOptions.size(), is(4));
|
||||
assertThat(stateOptions.get(0), not(nullValue()));
|
||||
assertThat(stateOptions.get(0).getValue(), is(source_1.name()));
|
||||
assertThat(stateOptions.get(0).getLabel(), is(sourceOneLabel));
|
||||
assertThat(stateOptions.get(1).getValue(), is(source_2.name()));
|
||||
assertThat(stateOptions.get(1).getLabel(), is("SHIELD")); // Overridden by user
|
||||
assertThat(stateOptions.get(2).getValue(), is(hdmi1.name()));
|
||||
assertThat(stateOptions.get(2).getLabel(), is("HDMI 1"));
|
||||
assertThat(stateOptions.get(3).getValue(), is(coax1.name()));
|
||||
assertThat(stateOptions.get(3).getLabel(), is("Coax 1"));
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup.AUDIO_INFO;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup.TUNER;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup.VIDEO_INFO;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands;
|
||||
import org.openhab.binding.emotiva.internal.protocol.EmotivaSubscriptionTagGroup;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EmotivaSubscriptionTagGroupHandler}.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class EmotivaSubscriptionTagGroupHandlerTest {
|
||||
|
||||
@Test
|
||||
void sourceTuner() {
|
||||
EmotivaConfiguration config = new EmotivaConfiguration();
|
||||
EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
var subscriptionHandler = new EmotivaSubscriptionTagGroupHandler(config, state);
|
||||
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups = (subscribeSet,
|
||||
unsubscribeSet) -> {
|
||||
assertThat(subscribeSet, hasItems(TUNER));
|
||||
assertThat(subscribeSet, not(hasItems(VIDEO_INFO)));
|
||||
assertThat(unsubscribeSet, hasItems(VIDEO_INFO));
|
||||
assertThat(unsubscribeSet, not(hasItems(TUNER)));
|
||||
};
|
||||
subscriptionHandler.tagGroupsFromSource(EmotivaControlCommands.tuner, tagGroups);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceAudioOnly() {
|
||||
EmotivaConfiguration config = new EmotivaConfiguration();
|
||||
EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
var subscriptionHandler = new EmotivaSubscriptionTagGroupHandler(config, state);
|
||||
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups = (subscribeSet,
|
||||
unsubscribeSet) -> {
|
||||
assertThat(subscribeSet, hasItems(AUDIO_INFO));
|
||||
assertThat(subscribeSet, not(hasItems(TUNER)));
|
||||
assertThat(unsubscribeSet, hasItems(TUNER));
|
||||
assertThat(unsubscribeSet, not(hasItems(AUDIO_INFO)));
|
||||
};
|
||||
subscriptionHandler.tagGroupsFromSource(EmotivaControlCommands.analog1, tagGroups);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceAudioAndVideo() {
|
||||
EmotivaConfiguration config = new EmotivaConfiguration();
|
||||
EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
var subscriptionHandler = new EmotivaSubscriptionTagGroupHandler(config, state);
|
||||
|
||||
BiConsumer<Set<EmotivaSubscriptionTagGroup>, Set<EmotivaSubscriptionTagGroup>> tagGroups = (subscribeSet,
|
||||
unsubscribeSet) -> {
|
||||
assertThat(subscribeSet, hasItems(AUDIO_INFO));
|
||||
assertThat(subscribeSet, hasItems(VIDEO_INFO));
|
||||
assertThat(subscribeSet, not(hasItems(TUNER)));
|
||||
assertThat(unsubscribeSet, hasItems(TUNER));
|
||||
assertThat(unsubscribeSet, not(hasItems(AUDIO_INFO)));
|
||||
assertThat(unsubscribeSet, not(hasItems(VIDEO_INFO)));
|
||||
};
|
||||
subscriptionHandler.tagGroupsFromSource(EmotivaControlCommands.hdmi1, tagGroups);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal.protocol;
|
||||
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.CHANNEL_FREQUENCY;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.CHANNEL_TREBLE;
|
||||
import static org.openhab.binding.emotiva.internal.EmotivaBindingConstants.CHANNEL_TUNER_CHANNEL;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.*;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.band_am;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.band_fm;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.openhab.binding.emotiva.internal.EmotivaProcessorState;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
|
||||
/**
|
||||
* Common setup for tests related to the {@link EmotivaControlCommands}.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AbstractEmotivaControlTest {
|
||||
|
||||
protected static final EnumMap<EmotivaControlCommands, String> MAP_SOURCES_MAIN_ZONE = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
protected static final EnumMap<EmotivaControlCommands, String> MAP_SOURCES_ZONE_2 = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
protected static final EnumMap<EmotivaControlCommands, String> CHANNEL_MAP = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
protected static final EnumMap<EmotivaControlCommands, String> RADIO_BAND_MAP = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
protected static final EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
MAP_SOURCES_MAIN_ZONE.put(source_1, "Input 1");
|
||||
MAP_SOURCES_MAIN_ZONE.put(source_2, "SHIELD");
|
||||
MAP_SOURCES_MAIN_ZONE.put(hdmi1, "HDMI 1");
|
||||
MAP_SOURCES_MAIN_ZONE.put(coax1, "Coax 1");
|
||||
state.setSourcesMainZone(MAP_SOURCES_MAIN_ZONE);
|
||||
|
||||
MAP_SOURCES_ZONE_2.put(source_1, "HDMI 1");
|
||||
MAP_SOURCES_ZONE_2.put(source_2, "SHIELD");
|
||||
MAP_SOURCES_ZONE_2.put(hdmi1, "HDMI 1");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_coax1, "Coax 1");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_ARC, "Audio Return Channel");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_follow_main, "Follow Main");
|
||||
state.setSourcesZone2(MAP_SOURCES_ZONE_2);
|
||||
|
||||
CHANNEL_MAP.put(channel_1, "Channel 1");
|
||||
CHANNEL_MAP.put(channel_2, "Channel 2");
|
||||
CHANNEL_MAP.put(channel_3, "My Radio Channel");
|
||||
state.setChannels(CHANNEL_MAP);
|
||||
|
||||
RADIO_BAND_MAP.put(band_am, "AM");
|
||||
RADIO_BAND_MAP.put(band_fm, "FM");
|
||||
state.setTunerBands(RADIO_BAND_MAP);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.emotiva.internal.protocol;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.analog1;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.hdmi1;
|
||||
import static org.openhab.binding.emotiva.internal.protocol.EmotivaControlCommands.source_2;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EmotivaControlCommands}.
|
||||
*
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class EmotivaControlCommandsTest extends AbstractEmotivaControlTest {
|
||||
|
||||
private static Stream<Arguments> mapInputToSourceCommand() {
|
||||
return Stream.of(Arguments.of("", "none", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of(" ", "none", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of(" ", "none", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("HDMI1", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("HDMI1\n", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("HDMI1\r", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("\n\rHDMI1\r\n", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("Hdmi1", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of(" Hdmi1 ", "hdmi1", Map.ofEntries(Map.entry(hdmi1, hdmi1.getLabel()))),
|
||||
Arguments.of("source_2", "source_2", Map.ofEntries(Map.entry(source_2, "SHIELD"))),
|
||||
Arguments.of("SHIELD", "source_2", Map.ofEntries(Map.entry(source_2, "SHIELD"))),
|
||||
Arguments.of("Analog 1", "analog1", Map.ofEntries(Map.entry(analog1, "Analog 1"))),
|
||||
Arguments.of("Analog1", "analog1", Map.ofEntries(Map.entry(analog1, "Analog1"))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mapInputToSourceCommand")
|
||||
void mapInputToSourceCommand2(String input, String expected,
|
||||
Map<EmotivaControlCommands, String> mainZoneSourceOverrides) {
|
||||
mainZoneSourceOverrides.forEach(state::updateSourcesMainZone);
|
||||
EmotivaControlCommands sourceCommand = EmotivaControlCommands.matchFromSourceInput(input,
|
||||
mainZoneSourceOverrides);
|
||||
assertThat(sourceCommand.name(), is(expected));
|
||||
}
|
||||
}
|
||||
+2
-45
@@ -19,17 +19,14 @@ 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.EnumMap;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.openhab.binding.emotiva.internal.EmotivaCommandHelper;
|
||||
import org.openhab.binding.emotiva.internal.EmotivaProcessorState;
|
||||
import org.openhab.binding.emotiva.internal.dto.EmotivaControlDTO;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
@@ -48,7 +45,7 @@ import org.openhab.core.types.UnDefType;
|
||||
* @author Espen Fossen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class EmotivaControlRequestTest {
|
||||
class EmotivaControlRequestTest extends AbstractEmotivaControlTest {
|
||||
|
||||
private static Stream<Arguments> channelToDTOs() {
|
||||
return Stream.of(Arguments.of(CHANNEL_STANDBY, OnOffType.ON, standby, PROTOCOL_V2, "0"),
|
||||
@@ -132,7 +129,7 @@ class EmotivaControlRequestTest {
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("HDMI1"), hdmi1, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("SHIELD"), source_2, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("hdmi1"), hdmi1, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("coax1"), none, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("coax1"), coax1, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("zone2_coax1"), zone2_coax1, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("zone2_ARC"), zone2_ARC, PROTOCOL_V2, "0"),
|
||||
Arguments.of(CHANNEL_ZONE2_SOURCE, new StringType("NOT_REAL"), none, PROTOCOL_V2, "0"),
|
||||
@@ -207,46 +204,6 @@ class EmotivaControlRequestTest {
|
||||
"-2.0"));
|
||||
}
|
||||
|
||||
private static final EnumMap<EmotivaControlCommands, String> MAP_SOURCES_MAIN_ZONE = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
private static final EnumMap<EmotivaControlCommands, String> MAP_SOURCES_ZONE_2 = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
private static final EnumMap<EmotivaControlCommands, String> CHANNEL_MAP = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
private static final EnumMap<EmotivaControlCommands, String> RADIO_BAND_MAP = new EnumMap<>(
|
||||
EmotivaControlCommands.class);
|
||||
private static final EmotivaProcessorState state = new EmotivaProcessorState();
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
MAP_SOURCES_MAIN_ZONE.put(source_1, "HDMI 1");
|
||||
MAP_SOURCES_MAIN_ZONE.put(source_2, "SHIELD");
|
||||
MAP_SOURCES_MAIN_ZONE.put(hdmi1, "HDMI1");
|
||||
MAP_SOURCES_MAIN_ZONE.put(coax1, "Coax 1");
|
||||
state.setSourcesMainZone(MAP_SOURCES_MAIN_ZONE);
|
||||
|
||||
MAP_SOURCES_ZONE_2.put(source_1, "HDMI 1");
|
||||
MAP_SOURCES_ZONE_2.put(source_2, "SHIELD");
|
||||
MAP_SOURCES_ZONE_2.put(hdmi1, "HDMI1");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_coax1, "Coax 1");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_ARC, "Audio Return Channel");
|
||||
MAP_SOURCES_ZONE_2.put(zone2_follow_main, "Follow Main");
|
||||
state.setSourcesZone2(MAP_SOURCES_ZONE_2);
|
||||
|
||||
CHANNEL_MAP.put(channel_1, "Channel 1");
|
||||
CHANNEL_MAP.put(channel_2, "Channel 2");
|
||||
CHANNEL_MAP.put(channel_3, "My Radio Channel");
|
||||
state.setChannels(CHANNEL_MAP);
|
||||
|
||||
RADIO_BAND_MAP.put(band_am, "AM");
|
||||
RADIO_BAND_MAP.put(band_fm, "FM");
|
||||
state.setTunerBands(RADIO_BAND_MAP);
|
||||
|
||||
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
|
||||
@MethodSource("channelToDTOs")
|
||||
void createDTO(String channel, Command ohValue, EmotivaControlCommands controlCommand,
|
||||
|
||||
Reference in New Issue
Block a user