*/
package org.openhab.binding.monopriceaudio.internal.communication;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.IntStream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.monopriceaudio.internal.configuration.MonopriceAudioThingConfiguration;
2, false, List.of("1", "2", "3", "4", "5", "6")) {
@Override
public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
- MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
+ final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
Matcher matcher = MONOPRICE70_PATTERN.matcher(newZoneData);
if (matcher.find()) {
false, List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16")) {
@Override
public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
- MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
- Matcher matcher = XANTECH_PATTERN.matcher(newZoneData);
+ final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
+ final Matcher matcher = XANTECH_PATTERN.matcher(newZoneData);
if (matcher.find()) {
zoneData.setZone(matcher.group(1));
// Used by 10761/DAX66 and DAX88
private static MonopriceAudioZoneDTO getMonopriceZoneData(String newZoneData) {
- MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
- Matcher matcher = MONOPRICE_PATTERN.matcher(newZoneData);
+ final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
+ final Matcher matcher = MONOPRICE_PATTERN.matcher(newZoneData);
if (matcher.find()) {
zoneData.setZone(matcher.group(1));
private static final Pattern XANTECH_PATTERN = Pattern.compile(
"^#(\\d{1,2})ZS PR(\\d{1}) SS(\\d{1}) VO(\\d{1,2}) MU(\\d{1}) TR(\\d{1,2}) BS(\\d{1,2}) BA(\\d{1,2}) LS(\\d{1}) PS(\\d{1})+");
- private String cmdPrefix;
- private String cmdSuffix;
- private String queryPrefix;
- private String querySuffix;
- private String respPrefix;
- private String powerCmd;
- private String sourceCmd;
- private String volumeCmd;
- private String muteCmd;
- private String trebleCmd;
- private String bassCmd;
- private String balanceCmd;
- private String dndCmd;
- private int maxVol;
- private int minTone;
- private int maxTone;
- private int toneOffset;
- private int minBal;
- private int maxBal;
- private int balOffset;
- private int maxZones;
- private int numSources;
- private boolean padNumbers;
- private List<String> zoneIds;
- private Map<String, String> zoneIdMap = new HashMap<>();
+ private final String cmdPrefix;
+ private final String cmdSuffix;
+ private final String queryPrefix;
+ private final String querySuffix;
+ private final String respPrefix;
+ private final String powerCmd;
+ private final String sourceCmd;
+ private final String volumeCmd;
+ private final String muteCmd;
+ private final String trebleCmd;
+ private final String bassCmd;
+ private final String balanceCmd;
+ private final String dndCmd;
+ private final int maxVol;
+ private final int minTone;
+ private final int maxTone;
+ private final int toneOffset;
+ private final int minBal;
+ private final int maxBal;
+ private final int balOffset;
+ private final int maxZones;
+ private final int numSources;
+ private final boolean padNumbers;
+ private final List<String> zoneIds;
+ private final Map<String, String> zoneIdMap;
private static final String ON_STR = "1";
private static final String OFF_STR = "0";
this.padNumbers = padNumbers;
this.zoneIds = zoneIds;
- int i = 1;
- for (String zoneId : zoneIds) {
- zoneIdMap.put(zoneId, "zone" + i);
- i++;
- }
+ // Build a map between the amp's physical zone IDs and the thing's logical zone names
+ final Map<String, String> zoneIdMap = new HashMap<>();
+ IntStream.range(0, zoneIds.size()).forEach(i -> zoneIdMap.put(zoneIds.get(i), "zone" + (i + 1)));
+ this.zoneIdMap = Collections.unmodifiableMap(zoneIdMap);
}
public abstract MonopriceAudioZoneDTO getZoneData(String newZoneData);
}
public String getFormattedValue(Integer value) {
- if (padNumbers) {
- return String.format("%02d", value);
- } else {
- return value.toString();
- }
+ return padNumbers ? String.format("%02d", value) : value.toString();
}
public String getOnStr() {
- if (padNumbers) {
- return ON_STR_PAD;
- } else {
- return ON_STR;
- }
+ return padNumbers ? ON_STR_PAD : ON_STR;
}
public String getOffStr() {
- if (padNumbers) {
- return OFF_STR_PAD;
- } else {
- return OFF_STR;
- }
+ return padNumbers ? OFF_STR_PAD : OFF_STR;
}
}
import org.openhab.binding.monopriceaudio.internal.MonopriceAudioStateDescriptionOptionProvider;
import org.openhab.binding.monopriceaudio.internal.communication.AmplifierModel;
import org.openhab.binding.monopriceaudio.internal.communication.MonopriceAudioConnector;
-import org.openhab.binding.monopriceaudio.internal.communication.MonopriceAudioDefaultConnector;
import org.openhab.binding.monopriceaudio.internal.communication.MonopriceAudioIpConnector;
import org.openhab.binding.monopriceaudio.internal.communication.MonopriceAudioMessageEvent;
import org.openhab.binding.monopriceaudio.internal.communication.MonopriceAudioMessageEventListener;
private @Nullable ScheduledFuture<?> reconnectJob;
private @Nullable ScheduledFuture<?> pollingJob;
- private MonopriceAudioConnector connector = new MonopriceAudioDefaultConnector();
+ private MonopriceAudioConnector connector = new MonopriceAudioIpConnector();
private Map<String, MonopriceAudioZoneDTO> zoneDataMap = Map.of(ZONE, new MonopriceAudioZoneDTO());
private Set<String> ignoreZones = new HashSet<>();
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
- String channel = channelUID.getId();
- String[] channelSplit = channel.split(CHANNEL_DELIMIT);
- String channelType = channelSplit[1];
- String zoneName = channelSplit[0];
- String zoneId = amp.getZoneIdFromZoneName(zoneName);
+ final String channel = channelUID.getId();
+ final String[] channelSplit = channel.split(CHANNEL_DELIMIT);
+ final String channelType = channelSplit[1];
+ final String zoneName = channelSplit[0];
+ final String zoneId = amp.getZoneIdFromZoneName(zoneName);
if (getThing().getStatus() != ThingStatus.ONLINE) {
logger.debug("Thing is not ONLINE; command {} from channel {} is ignored", command, channel);
return;
}
- Stream<String> zoneStream = amp.getZoneIds().stream().limit(numZones);
try {
- switch (channelType) {
- case CHANNEL_TYPE_POWER:
- if (command instanceof OnOffType) {
- connector.sendCommand(zoneId, amp.getPowerCmd(), command == OnOffType.ON ? ONE : ZERO);
- zoneDataMap.get(zoneId)
- .setPower(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
- }
- break;
- case CHANNEL_TYPE_SOURCE:
- if (command instanceof DecimalType decimalCommand) {
- final int value = decimalCommand.intValue();
- if (value >= ONE && value <= amp.getNumSources()) {
- logger.debug("Got source command {} zone {}", value, zoneId);
- connector.sendCommand(zoneId, amp.getSourceCmd(), value);
- zoneDataMap.get(zoneId).setSource(amp.getFormattedValue(value));
+ if (!"all".equals(zoneName)) {
+ MonopriceAudioZoneDTO dto = zoneDataMap.get(zoneId);
+ if (dto == null) {
+ logger.debug("no zoneData for zoneId: {}", zoneId);
+ return;
+ }
+
+ switch (channelType) {
+ case CHANNEL_TYPE_POWER:
+ if (command instanceof OnOffType) {
+ connector.sendCommand(zoneId, amp.getPowerCmd(), command == OnOffType.ON ? ONE : ZERO);
+ dto.setPower(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
}
- }
- break;
- case CHANNEL_TYPE_VOLUME:
- if (command instanceof PercentType percentCommand) {
- final int value = (int) Math
- .round(percentCommand.doubleValue() / 100.0 * (amp.getMaxVol() - MIN_VOLUME))
- + MIN_VOLUME;
- logger.debug("Got volume command {} zone {}", value, zoneId);
- connector.sendCommand(zoneId, amp.getVolumeCmd(), value);
- zoneDataMap.get(zoneId).setVolume(value);
- }
- break;
- case CHANNEL_TYPE_MUTE:
- if (command instanceof OnOffType) {
- connector.sendCommand(zoneId, amp.getMuteCmd(), command == OnOffType.ON ? ONE : ZERO);
- zoneDataMap.get(zoneId).setMute(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
- }
- break;
- case CHANNEL_TYPE_TREBLE:
- if (command instanceof DecimalType decimalCommand) {
- final int value = decimalCommand.intValue();
- if (value >= amp.getMinTone() && value <= amp.getMaxTone()) {
- logger.debug("Got treble command {} zone {}", value, zoneId);
- connector.sendCommand(zoneId, amp.getTrebleCmd(), value + amp.getToneOffset());
- zoneDataMap.get(zoneId).setTreble(value + amp.getToneOffset());
+ break;
+ case CHANNEL_TYPE_SOURCE:
+ if (command instanceof DecimalType decimalCommand) {
+ final int value = decimalCommand.intValue();
+ if (value >= ONE && value <= amp.getNumSources()) {
+ logger.debug("Got source command {} zone {}", value, zoneId);
+ connector.sendCommand(zoneId, amp.getSourceCmd(), value);
+ dto.setSource(amp.getFormattedValue(value));
+ }
}
- }
- break;
- case CHANNEL_TYPE_BASS:
- if (command instanceof DecimalType decimalCommand) {
- final int value = decimalCommand.intValue();
- if (value >= amp.getMinTone() && value <= amp.getMaxTone()) {
- logger.debug("Got bass command {} zone {}", value, zoneId);
- connector.sendCommand(zoneId, amp.getBassCmd(), value + amp.getToneOffset());
- zoneDataMap.get(zoneId).setBass(value + amp.getToneOffset());
+ break;
+ case CHANNEL_TYPE_VOLUME:
+ if (command instanceof PercentType percentCommand) {
+ final int value = (int) Math
+ .round(percentCommand.doubleValue() / 100.0 * (amp.getMaxVol() - MIN_VOLUME))
+ + MIN_VOLUME;
+ logger.debug("Got volume command {} zone {}", value, zoneId);
+ connector.sendCommand(zoneId, amp.getVolumeCmd(), value);
+ dto.setVolume(value);
}
- }
- break;
- case CHANNEL_TYPE_BALANCE:
- if (command instanceof DecimalType decimalCommand) {
- final int value = decimalCommand.intValue();
- if (value >= amp.getMinBal() && value <= amp.getMaxBal()) {
- logger.debug("Got balance command {} zone {}", value, zoneId);
- connector.sendCommand(zoneId, amp.getBalanceCmd(), value + amp.getBalOffset());
- zoneDataMap.get(zoneId).setBalance(value + amp.getBalOffset());
+ break;
+ case CHANNEL_TYPE_MUTE:
+ if (command instanceof OnOffType) {
+ connector.sendCommand(zoneId, amp.getMuteCmd(), command == OnOffType.ON ? ONE : ZERO);
+ dto.setMute(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
}
- }
- break;
- case CHANNEL_TYPE_DND:
- if (command instanceof OnOffType) {
- connector.sendCommand(zoneId, amp.getDndCmd(), command == OnOffType.ON ? ONE : ZERO);
- zoneDataMap.get(zoneId).setDnd(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
- }
- break;
- case CHANNEL_TYPE_ALLPOWER:
- if (command instanceof OnOffType) {
- final int cmd = command == OnOffType.ON ? ONE : ZERO;
- zoneStream.forEach((streamZoneId) -> {
- if (command == OnOffType.OFF || !ignoreZones.contains(amp.getZoneName(streamZoneId))) {
- try {
- connector.sendCommand(streamZoneId, amp.getPowerCmd(), cmd);
- zoneDataMap.get(streamZoneId).setPower(amp.getFormattedValue(cmd));
- updateChannelState(streamZoneId, CHANNEL_TYPE_POWER);
-
- if (command == OnOffType.ON) {
- // reset the volume of each zone to allVolume
- connector.sendCommand(streamZoneId, amp.getVolumeCmd(), allVolume);
- zoneDataMap.get(streamZoneId).setVolume(allVolume);
- updateChannelState(streamZoneId, CHANNEL_TYPE_VOLUME);
- }
- } catch (MonopriceAudioException e) {
- logger.debug("Error Turning All Zones On: {}", e.getMessage());
- }
+ break;
+ case CHANNEL_TYPE_TREBLE:
+ if (command instanceof DecimalType decimalCommand) {
+ final int value = decimalCommand.intValue();
+ if (value >= amp.getMinTone() && value <= amp.getMaxTone()) {
+ logger.debug("Got treble command {} zone {}", value, zoneId);
+ connector.sendCommand(zoneId, amp.getTrebleCmd(), value + amp.getToneOffset());
+ dto.setTreble(value + amp.getToneOffset());
+ }
+ }
+ break;
+ case CHANNEL_TYPE_BASS:
+ if (command instanceof DecimalType decimalCommand) {
+ final int value = decimalCommand.intValue();
+ if (value >= amp.getMinTone() && value <= amp.getMaxTone()) {
+ logger.debug("Got bass command {} zone {}", value, zoneId);
+ connector.sendCommand(zoneId, amp.getBassCmd(), value + amp.getToneOffset());
+ dto.setBass(value + amp.getToneOffset());
}
+ }
+ break;
+ case CHANNEL_TYPE_BALANCE:
+ if (command instanceof DecimalType decimalCommand) {
+ final int value = decimalCommand.intValue();
+ if (value >= amp.getMinBal() && value <= amp.getMaxBal()) {
+ logger.debug("Got balance command {} zone {}", value, zoneId);
+ connector.sendCommand(zoneId, amp.getBalanceCmd(), value + amp.getBalOffset());
+ dto.setBalance(value + amp.getBalOffset());
+ }
+ }
+ break;
+ case CHANNEL_TYPE_DND:
+ if (command instanceof OnOffType) {
+ connector.sendCommand(zoneId, amp.getDndCmd(), command == OnOffType.ON ? ONE : ZERO);
+ dto.setDnd(command == OnOffType.ON ? amp.getOnStr() : amp.getOffStr());
+ }
+ break;
+ default:
+ success = false;
+ logger.debug("Command {} from channel {} failed: unexpected command", command, channel);
+ break;
+ }
+ } else {
+ Stream<String> zoneStream = amp.getZoneIds().stream().limit(numZones);
- });
- }
- break;
- case CHANNEL_TYPE_ALLSOURCE:
- if (command instanceof DecimalType decimalCommand) {
- final int value = decimalCommand.intValue();
- if (value >= ONE && value <= amp.getNumSources()) {
+ switch (channelType) {
+ case CHANNEL_TYPE_ALLPOWER:
+ if (command instanceof OnOffType) {
+ final int cmd = command == OnOffType.ON ? ONE : ZERO;
zoneStream.forEach((streamZoneId) -> {
- if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
+ if (command == OnOffType.OFF
+ || !ignoreZones.contains(amp.getZoneName(streamZoneId))) {
try {
- connector.sendCommand(streamZoneId, amp.getSourceCmd(), value);
- if (zoneDataMap.get(streamZoneId).isPowerOn()
- && !zoneDataMap.get(streamZoneId).isMuted()) {
- zoneDataMap.get(streamZoneId).setSource(amp.getFormattedValue(value));
- updateChannelState(streamZoneId, CHANNEL_TYPE_SOURCE);
+ MonopriceAudioZoneDTO streamDto = zoneDataMap.get(streamZoneId);
+ if (streamDto != null) {
+ connector.sendCommand(streamZoneId, amp.getPowerCmd(), cmd);
+ streamDto.setPower(amp.getFormattedValue(cmd));
+ updateChannelState(streamZoneId, CHANNEL_TYPE_POWER);
+
+ if (command == OnOffType.ON) {
+ // reset the volume of each zone to allVolume
+ connector.sendCommand(streamZoneId, amp.getVolumeCmd(), allVolume);
+ streamDto.setVolume(allVolume);
+ updateChannelState(streamZoneId, CHANNEL_TYPE_VOLUME);
+ }
}
} catch (MonopriceAudioException e) {
- logger.debug("Error Setting Source for All Zones: {}", e.getMessage());
+ logger.debug("Error Turning All Zones On: {}", e.getMessage());
}
}
+
});
}
- }
- break;
- case CHANNEL_TYPE_ALLVOLUME:
- if (command instanceof PercentType percentCommand) {
- allVolume = (int) Math
- .round(percentCommand.doubleValue() / 100.0 * (amp.getMaxVol() - MIN_VOLUME))
- + MIN_VOLUME;
- zoneStream.forEach((streamZoneId) -> {
- if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
- try {
- connector.sendCommand(streamZoneId, amp.getVolumeCmd(), allVolume);
- if (zoneDataMap.get(streamZoneId).isPowerOn()
- && !zoneDataMap.get(streamZoneId).isMuted()) {
- zoneDataMap.get(streamZoneId).setVolume(allVolume);
- updateChannelState(streamZoneId, CHANNEL_TYPE_VOLUME);
+ break;
+ case CHANNEL_TYPE_ALLSOURCE:
+ if (command instanceof DecimalType decimalCommand) {
+ final int value = decimalCommand.intValue();
+ if (value >= ONE && value <= amp.getNumSources()) {
+ zoneStream.forEach((streamZoneId) -> {
+ if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
+ try {
+ MonopriceAudioZoneDTO streamDto = zoneDataMap.get(streamZoneId);
+ if (streamDto != null) {
+ connector.sendCommand(streamZoneId, amp.getSourceCmd(), value);
+ if (streamDto.isPowerOn() && !streamDto.isMuted()) {
+ streamDto.setSource(amp.getFormattedValue(value));
+ updateChannelState(streamZoneId, CHANNEL_TYPE_SOURCE);
+ }
+ }
+ } catch (MonopriceAudioException e) {
+ logger.debug("Error Setting Source for All Zones: {}", e.getMessage());
+ }
}
- } catch (MonopriceAudioException e) {
- logger.debug("Error Setting Volume for All Zones: {}", e.getMessage());
- }
+ });
}
- });
- }
- break;
- case CHANNEL_TYPE_ALLMUTE:
- if (command instanceof OnOffType) {
- final int cmd = command == OnOffType.ON ? ONE : ZERO;
- zoneStream.forEach((streamZoneId) -> {
- if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
- try {
- connector.sendCommand(streamZoneId, amp.getMuteCmd(), cmd);
- if (zoneDataMap.get(streamZoneId).isPowerOn()) {
- zoneDataMap.get(streamZoneId).setMute(amp.getFormattedValue(cmd));
- updateChannelState(streamZoneId, CHANNEL_TYPE_MUTE);
+ }
+ break;
+ case CHANNEL_TYPE_ALLVOLUME:
+ if (command instanceof PercentType percentCommand) {
+ allVolume = (int) Math
+ .round(percentCommand.doubleValue() / 100.0 * (amp.getMaxVol() - MIN_VOLUME))
+ + MIN_VOLUME;
+ zoneStream.forEach((streamZoneId) -> {
+ if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
+ try {
+ MonopriceAudioZoneDTO streamDto = zoneDataMap.get(streamZoneId);
+ if (streamDto != null) {
+ connector.sendCommand(streamZoneId, amp.getVolumeCmd(), allVolume);
+ if (streamDto.isPowerOn() && !streamDto.isMuted()) {
+ streamDto.setVolume(allVolume);
+ updateChannelState(streamZoneId, CHANNEL_TYPE_VOLUME);
+ }
+ }
+ } catch (MonopriceAudioException e) {
+ logger.debug("Error Setting Volume for All Zones: {}", e.getMessage());
}
- } catch (MonopriceAudioException e) {
- logger.debug("Error Setting Mute for All Zones: {}", e.getMessage());
}
- }
- });
- }
- break;
- default:
- success = false;
- logger.debug("Command {} from channel {} failed: unexpected command", command, channel);
- break;
+ });
+ }
+ break;
+ case CHANNEL_TYPE_ALLMUTE:
+ if (command instanceof OnOffType) {
+ final int cmd = command == OnOffType.ON ? ONE : ZERO;
+ zoneStream.forEach((streamZoneId) -> {
+ if (!ignoreZones.contains(amp.getZoneName(streamZoneId))) {
+ try {
+ MonopriceAudioZoneDTO streamDto = zoneDataMap.get(streamZoneId);
+ if (streamDto != null) {
+ connector.sendCommand(streamZoneId, amp.getMuteCmd(), cmd);
+ if (streamDto.isPowerOn()) {
+ streamDto.setMute(amp.getFormattedValue(cmd));
+ updateChannelState(streamZoneId, CHANNEL_TYPE_MUTE);
+ }
+ }
+ } catch (MonopriceAudioException e) {
+ logger.debug("Error Setting Mute for All Zones: {}", e.getMessage());
+ }
+ }
+ });
+ }
+ break;
+ default:
+ success = false;
+ logger.debug("Command {} from all channel {} failed: unexpected command", command, channel);
+ break;
+ }
}
if (success) {
@Override
public void onNewMessageEvent(MonopriceAudioMessageEvent evt) {
updateStatus(ThingStatus.ONLINE);
- String key = evt.getKey();
- switch (key) {
+ switch (evt.getKey()) {
case MonopriceAudioConnector.KEY_ZONE_UPDATE:
MonopriceAudioZoneDTO newZoneData = amp.getZoneData(evt.getValue());
MonopriceAudioZoneDTO zoneData = zoneDataMap.get(newZoneData.getZone());
processZoneUpdate(zoneData, newZoneData);
}
} else {
- logger.debug("invalid event: {} for key: {} or zone data null", evt.getValue(), key);
+ logger.debug("invalid event: {} for key: {} or zone data null", evt.getValue(), evt.getKey());
}
break;
break;
default:
- logger.debug("onNewMessageEvent: unhandled key {}", key);
+ logger.debug("onNewMessageEvent: unhandled key {}", evt.getKey());
break;
}
}