From 51f3bf6b867b754b6d7832d615d70b2c09ba711c Mon Sep 17 00:00:00 2001 From: mlobstein Date: Mon, 24 Jul 2023 18:17:49 -0500 Subject: [PATCH] [nuvo] Include NuvoNet source favorites in zone `favorite` channel (#15292) * Include NuvoNet source favorites in zone `favorite` channel * Use existing constants * VALID_SOURCES to enum list Signed-off-by: Michael Lobstein --- bundles/org.openhab.binding.nuvo/README.md | 2 +- .../nuvo/internal/NuvoBindingConstants.java | 3 +- .../nuvo/internal/communication/NuvoEnum.java | 74 ++-- .../nuvo/internal/handler/NuvoHandler.java | 364 +++++++++--------- 4 files changed, 235 insertions(+), 208 deletions(-) diff --git a/bundles/org.openhab.binding.nuvo/README.md b/bundles/org.openhab.binding.nuvo/README.md index 72c60c788f099..cf486d0d8290c 100644 --- a/bundles/org.openhab.binding.nuvo/README.md +++ b/bundles/org.openhab.binding.nuvo/README.md @@ -91,7 +91,7 @@ The following channels are available: | zoneN#source (where N= 1-20) | Number | Select the source input for a zone (1-6) | | zoneN#volume (where N= 1-20) | Dimmer | Control the volume for a zone (0-100%) [translates to 0-79] | | zoneN#mute (where N= 1-20) | Switch | Mute or unmute a zone | -| zoneN#favorite (where N= 1-20) | Number | Select a preset Favorite for a zone (1-12) | +| zoneN#favorite (where N= 1-20) | Number | Select a preset Favorite for a zone (1-12). Also will display and can select any favorite specified in openHAB NuvoNet sources | | zoneN#control (where N= 1-20) | Player | Simulate pressing the transport control buttons on the keypad e.g. play/pause/next/previous | | zoneN#treble (where N= 1-20) | Number | Adjust the treble control for a zone (-18 to 18 [in increments of 2]) -18=none, 0=flat, 18=full | | zoneN#bass (where N= 1-20) | Number | Adjust the bass control for a zone (-18 to 18 [in increments of 2]) -18=none, 0=flat, 18=full | diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java index e0c78e2be7b2c..b4248a5fcf8ff 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java @@ -105,10 +105,9 @@ public class NuvoBindingConstants { public static final String TYPE_RESTART = "RESTART"; public static final String DISABLE = "disable"; public static final String ALBUM_ART_ID = "albumartid"; - public static final String SRC_KEY = "S"; - public static final String ZONE_KEY = "Z"; public static final String ALBUM_ART_AVAILABLE = "ALBUMARTAVAILABLE"; public static final String ALBUM_ART_FRAG = "ALBUMARTFRAG"; public static final String HTTP = "http://"; public static final String HTTPS = "https://"; + public static final String PLAY_MUSIC_PRESET = "PLAY_MUSIC_PRESET:"; } diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoEnum.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoEnum.java index d66f5fa1e1195..5d744e9e4d094 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoEnum.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoEnum.java @@ -14,7 +14,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -25,44 +24,46 @@ */ @NonNullByDefault public enum NuvoEnum { - SYSTEM("SYSTEM", "SYSTEM"), - ZONE1("Z1", "ZCFG1"), - ZONE2("Z2", "ZCFG2"), - ZONE3("Z3", "ZCFG3"), - ZONE4("Z4", "ZCFG4"), - ZONE5("Z5", "ZCFG5"), - ZONE6("Z6", "ZCFG6"), - ZONE7("Z7", "ZCFG7"), - ZONE8("Z8", "ZCFG8"), - ZONE9("Z9", "ZCFG9"), - ZONE10("Z10", "ZCFG10"), - ZONE11("Z11", "ZCFG11"), - ZONE12("Z12", "ZCFG12"), - ZONE13("Z13", "ZCFG13"), - ZONE14("Z14", "ZCFG14"), - ZONE15("Z15", "ZCFG15"), - ZONE16("Z16", "ZCFG16"), - ZONE17("Z17", "ZCFG17"), - ZONE18("Z18", "ZCFG18"), - ZONE19("Z19", "ZCFG19"), - ZONE20("Z20", "ZCFG20"), - SOURCE1("S1", "SCFG1"), - SOURCE2("S2", "SCFG2"), - SOURCE3("S3", "SCFG3"), - SOURCE4("S4", "SCFG4"), - SOURCE5("S5", "SCFG5"), - SOURCE6("S6", "SCFG6"); + SYSTEM("SYSTEM", "SYSTEM", 0), + ZONE1("Z1", "ZCFG1", 1), + ZONE2("Z2", "ZCFG2", 2), + ZONE3("Z3", "ZCFG3", 3), + ZONE4("Z4", "ZCFG4", 4), + ZONE5("Z5", "ZCFG5", 5), + ZONE6("Z6", "ZCFG6", 6), + ZONE7("Z7", "ZCFG7", 7), + ZONE8("Z8", "ZCFG8", 8), + ZONE9("Z9", "ZCFG9", 9), + ZONE10("Z10", "ZCFG10", 10), + ZONE11("Z11", "ZCFG11", 11), + ZONE12("Z12", "ZCFG12", 12), + ZONE13("Z13", "ZCFG13", 13), + ZONE14("Z14", "ZCFG14", 14), + ZONE15("Z15", "ZCFG15", 15), + ZONE16("Z16", "ZCFG16", 16), + ZONE17("Z17", "ZCFG17", 17), + ZONE18("Z18", "ZCFG18", 18), + ZONE19("Z19", "ZCFG19", 19), + ZONE20("Z20", "ZCFG20", 20), + SOURCE1("S1", "SCFG1", 1), + SOURCE2("S2", "SCFG2", 2), + SOURCE3("S3", "SCFG3", 3), + SOURCE4("S4", "SCFG4", 4), + SOURCE5("S5", "SCFG5", 5), + SOURCE6("S6", "SCFG6", 6); private final String id; private final String cfgId; + private final int num; - // make a list of all valid source ids - public static final List VALID_SOURCES = Arrays.stream(values()).map(NuvoEnum::name) - .filter(s -> s.contains("SOURCE")).collect(Collectors.toList()); + // make a list of all valid source enums + public static final List VALID_SOURCES = Arrays.stream(values()).filter(s -> s.name().contains("SOURCE")) + .toList(); - NuvoEnum(String id, String cfgId) { + NuvoEnum(String id, String cfgId, int num) { this.id = id; this.cfgId = cfgId; + this.num = num; } /** @@ -82,4 +83,13 @@ public String getId() { public String getConfigId() { return cfgId; } + + /** + * Get the num + * + * @return the num + */ + public int getNum() { + return num; + } } diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java index 5a8ecab0b0ecb..c55ea48aae213 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java @@ -158,13 +158,13 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis private boolean isAnyOhNuvoNet = false; private NuvoMenu nuvoMenus = new NuvoMenu(); private HashMap> nuvoGroupMap = new HashMap>(); - private HashMap nuvoNetSrcMap = new HashMap(); - private HashMap favPrefixMap = new HashMap(); - private HashMap favoriteMap = new HashMap(); + private HashMap nuvoNetSrcMap = new HashMap(); + private HashMap favPrefixMap = new HashMap(); + private HashMap favoriteMap = new HashMap(); - private HashMap albumArtMap = new HashMap(); - private HashMap albumArtIds = new HashMap(); - private HashMap dispInfoCache = new HashMap(); + private HashMap albumArtMap = new HashMap(); + private HashMap albumArtIds = new HashMap(); + private HashMap dispInfoCache = new HashMap(); Set activeZones = new HashSet<>(1); @@ -227,12 +227,12 @@ public void initialize() { return; } - nuvoNetSrcMap.put("1", config.nuvoNetSrc1); - nuvoNetSrcMap.put("2", config.nuvoNetSrc2); - nuvoNetSrcMap.put("3", config.nuvoNetSrc3); - nuvoNetSrcMap.put("4", config.nuvoNetSrc4); - nuvoNetSrcMap.put("5", config.nuvoNetSrc5); - nuvoNetSrcMap.put("6", config.nuvoNetSrc6); + nuvoNetSrcMap.put(NuvoEnum.SOURCE1, config.nuvoNetSrc1); + nuvoNetSrcMap.put(NuvoEnum.SOURCE2, config.nuvoNetSrc2); + nuvoNetSrcMap.put(NuvoEnum.SOURCE3, config.nuvoNetSrc3); + nuvoNetSrcMap.put(NuvoEnum.SOURCE4, config.nuvoNetSrc4); + nuvoNetSrcMap.put(NuvoEnum.SOURCE5, config.nuvoNetSrc5); + nuvoNetSrcMap.put(NuvoEnum.SOURCE6, config.nuvoNetSrc6); nuvoGroupMap.put("1", new HashSet()); nuvoGroupMap.put("2", new HashSet()); @@ -242,47 +242,48 @@ public void initialize() { if (this.isMps4) { logger.debug("Port set to {} configuring binding for MPS4 compatability", MPS4_PORT); - this.isAnyOhNuvoNet = (config.nuvoNetSrc1 == 2 || config.nuvoNetSrc2 == 2 || config.nuvoNetSrc3 == 2 - || config.nuvoNetSrc4 == 2 || config.nuvoNetSrc5 == 2 || config.nuvoNetSrc6 == 2); + this.isAnyOhNuvoNet = (config.nuvoNetSrc1.equals(2) || config.nuvoNetSrc2.equals(2) + || config.nuvoNetSrc3.equals(2) || config.nuvoNetSrc4.equals(2) || config.nuvoNetSrc5.equals(2) + || config.nuvoNetSrc6.equals(2)); if (this.isAnyOhNuvoNet) { logger.debug("At least one source is configured as an openHAB NuvoNet source"); connector.setAnyOhNuvoNet(true); loadMenuConfiguration(config); - favoriteMap.put("1", + favoriteMap.put(NuvoEnum.SOURCE1, !config.favoritesSrc1.isEmpty() ? config.favoritesSrc1.split(COMMA) : new String[0]); - favoriteMap.put("2", + favoriteMap.put(NuvoEnum.SOURCE2, !config.favoritesSrc2.isEmpty() ? config.favoritesSrc2.split(COMMA) : new String[0]); - favoriteMap.put("3", + favoriteMap.put(NuvoEnum.SOURCE3, !config.favoritesSrc3.isEmpty() ? config.favoritesSrc3.split(COMMA) : new String[0]); - favoriteMap.put("4", + favoriteMap.put(NuvoEnum.SOURCE4, !config.favoritesSrc4.isEmpty() ? config.favoritesSrc4.split(COMMA) : new String[0]); - favoriteMap.put("5", + favoriteMap.put(NuvoEnum.SOURCE5, !config.favoritesSrc5.isEmpty() ? config.favoritesSrc5.split(COMMA) : new String[0]); - favoriteMap.put("6", + favoriteMap.put(NuvoEnum.SOURCE6, !config.favoritesSrc6.isEmpty() ? config.favoritesSrc6.split(COMMA) : new String[0]); - favPrefixMap.put("1", config.favPrefix1); - favPrefixMap.put("2", config.favPrefix2); - favPrefixMap.put("3", config.favPrefix3); - favPrefixMap.put("4", config.favPrefix4); - favPrefixMap.put("5", config.favPrefix5); - favPrefixMap.put("6", config.favPrefix6); - - albumArtIds.put("S1", 0); - albumArtIds.put("S2", 0); - albumArtIds.put("S3", 0); - albumArtIds.put("S4", 0); - albumArtIds.put("S5", 0); - albumArtIds.put("S6", 0); - - albumArtMap.put("S1", NO_ART); - albumArtMap.put("S2", NO_ART); - albumArtMap.put("S3", NO_ART); - albumArtMap.put("S4", NO_ART); - albumArtMap.put("S5", NO_ART); - albumArtMap.put("S6", NO_ART); + favPrefixMap.put(NuvoEnum.SOURCE1, config.favPrefix1); + favPrefixMap.put(NuvoEnum.SOURCE2, config.favPrefix2); + favPrefixMap.put(NuvoEnum.SOURCE3, config.favPrefix3); + favPrefixMap.put(NuvoEnum.SOURCE4, config.favPrefix4); + favPrefixMap.put(NuvoEnum.SOURCE5, config.favPrefix5); + favPrefixMap.put(NuvoEnum.SOURCE6, config.favPrefix6); + + albumArtIds.put(NuvoEnum.SOURCE1, 0); + albumArtIds.put(NuvoEnum.SOURCE2, 0); + albumArtIds.put(NuvoEnum.SOURCE3, 0); + albumArtIds.put(NuvoEnum.SOURCE4, 0); + albumArtIds.put(NuvoEnum.SOURCE5, 0); + albumArtIds.put(NuvoEnum.SOURCE6, 0); + + albumArtMap.put(NuvoEnum.SOURCE1, NO_ART); + albumArtMap.put(NuvoEnum.SOURCE2, NO_ART); + albumArtMap.put(NuvoEnum.SOURCE3, NO_ART); + albumArtMap.put(NuvoEnum.SOURCE4, NO_ART); + albumArtMap.put(NuvoEnum.SOURCE5, NO_ART); + albumArtMap.put(NuvoEnum.SOURCE6, NO_ART); } } @@ -306,7 +307,7 @@ public void initialize() { // Build a list of State options for the global favorites using user config values (if supplied) String[] favoritesArr = !config.favoriteLabels.isEmpty() ? config.favoriteLabels.split(COMMA) : new String[0]; List favoriteLabelsStateOptions = new ArrayList<>(); - for (int i = 0; i < 12; i++) { + for (int i = 0; i < MAX_FAV; i++) { if (favoritesArr.length > i) { favoriteLabelsStateOptions.add(new StateOption(String.valueOf(i + 1), favoritesArr[i])); } else if (favoritesArr.length == 0) { @@ -314,6 +315,18 @@ public void initialize() { } } + // Also add any openHAB NuvoNet source favorites to the list + for (int src = 1; src <= MAX_SRC; src++) { + NuvoEnum source = NuvoEnum.valueOf(SOURCE + String.valueOf(src)); + String[] favorites = favoriteMap.get(source); + if (favorites != null) { + for (int fav = 0; fav < favorites.length; fav++) { + favoriteLabelsStateOptions.add(new StateOption(String.valueOf(src * 100 + fav), + favPrefixMap.get(source) + favorites[fav])); + } + } + } + // Put the global favorites labels on all active zones activeZones.forEach(zoneNum -> { stateDescriptionProvider.setStateOptions( @@ -337,29 +350,29 @@ public void dispose() { if (this.isAnyOhNuvoNet) { try { // disable NuvoNet for each source that was configured as an openHAB NuvoNet source - nuvoNetSrcMap.forEach((srcNum, val) -> { - if (val == 2) { + nuvoNetSrcMap.forEach((source, val) -> { + if (val.equals(2)) { try { - connector.sendCommand(SRC_KEY + srcNum + "DISPINFOTWO0,0,0,0,0,0,0"); + connector.sendCommand(source.getId() + "DISPINFOTWO0,0,0,0,0,0,0"); Thread.sleep(SLEEP_BETWEEN_CMD_MS); connector.sendCommand( - SRC_KEY + srcNum + "DISPLINES0,0,0,\"Source Unavailable\",\"\",\"\",\"\""); + source.getId() + "DISPLINES0,0,0,\"Source Unavailable\",\"\",\"\",\"\""); Thread.sleep(SLEEP_BETWEEN_CMD_MS); - connector.sendCommand("SCFG" + srcNum + "NUVONET0"); + connector.sendCommand(source.getConfigId() + "NUVONET0"); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } catch (NuvoException | InterruptedException e) { - logger.debug("Error sending command to disable NuvoNet source: {}", srcNum); + logger.debug("Error sending command to disable NuvoNet source: {}", source.getNum()); } } }); // need '1' flag for sources configured as an MPS4 NuvoNet source, but disable openHAB NuvoNet sources - connector.sendCommand("SNUMBERS" + (nuvoNetSrcMap.get("1") == 1 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("2") == 1 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("3") == 1 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("4") == 1 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("5") == 1 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("6") == 1 ? ONE : ZERO)); + connector.sendCommand("SNUMBERS" + (nuvoNetSrcMap.get(NuvoEnum.SOURCE1).equals(1) ? ONE : ZERO) + COMMA + + (nuvoNetSrcMap.get(NuvoEnum.SOURCE2).equals(1) ? ONE : ZERO) + COMMA + + (nuvoNetSrcMap.get(NuvoEnum.SOURCE3).equals(1) ? ONE : ZERO) + COMMA + + (nuvoNetSrcMap.get(NuvoEnum.SOURCE4).equals(1) ? ONE : ZERO) + COMMA + + (nuvoNetSrcMap.get(NuvoEnum.SOURCE5).equals(1) ? ONE : ZERO) + COMMA + + (nuvoNetSrcMap.get(NuvoEnum.SOURCE6).equals(1) ? ONE : ZERO)); } catch (NuvoException e) { logger.debug("Error sending SNUMBERS command to disable NuvoNet sources"); } @@ -439,6 +452,15 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (value >= 1 && value <= MAX_FAV) { logger.debug("Got favorite command {} zone {}", value, target); connector.sendCommand(target, NuvoCommand.FAVORITE, String.valueOf(value)); + } else if (value >= 100 && value <= 650) { + String sourceNum = String.valueOf(value / 100); + NuvoEnum source = NuvoEnum.valueOf(SOURCE + sourceNum); + updateChannelState(source, CHANNEL_BUTTON_PRESS, + PLAY_MUSIC_PRESET + favoriteMap.get(source)[value % 100]); + connector.sendCommand(target, NuvoCommand.SOURCE, sourceNum); + + // if this zone is in a group, update the other group member's selected source + updateSrcForZoneGroup(target, sourceNum); } } break; @@ -557,12 +579,13 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (command instanceof StringType) { String commandStr = command.toString(); if (commandStr.contains(DISP_INFO_TWO)) { - String sourceKey = commandStr.split(DISP_INFO_TWO)[0]; - dispInfoCache.put(sourceKey, commandStr); + NuvoEnum source = NuvoEnum + .valueOf(commandStr.split(DISP_INFO_TWO)[0].replace("S", SOURCE)); + dispInfoCache.put(source, commandStr); // if 'albumartid' is present, substitute it with the albumArtId hex string connector.sendCommand(commandStr.replace(ALBUM_ART_ID, - (OFFSET_ZERO + Integer.toHexString(albumArtIds.get(sourceKey))))); + (OFFSET_ZERO + Integer.toHexString(albumArtIds.get(source))))); } else { connector.sendCommand(commandStr); } @@ -577,33 +600,33 @@ public void handleCommand(ChannelUID channelUID, Command command) { .timeout(10, TimeUnit.SECONDS).send(); int httpStatus = contentResponse.getStatus(); if (httpStatus == OK_200) { - albumArtMap.put(target.getId(), + albumArtMap.put(target, NuvoImageResizer.resizeImage(contentResponse.getContent(), 80, 80)); updateChannelState(target, CHANNEL_ALBUM_ART, BLANK, contentResponse.getContent()); } else { - albumArtMap.put(target.getId(), NO_ART); - albumArtIds.put(target.getId(), 0); + albumArtMap.put(target, NO_ART); + albumArtIds.put(target, 0); updateChannelState(target, CHANNEL_ALBUM_ART, UNDEF); return; } } catch (InterruptedException | TimeoutException | ExecutionException e) { - albumArtMap.put(target.getId(), NO_ART); - albumArtIds.put(target.getId(), 0); + albumArtMap.put(target, NO_ART); + albumArtIds.put(target, 0); updateChannelState(target, CHANNEL_ALBUM_ART, UNDEF); return; } - albumArtIds.put(target.getId(), Math.abs(url.hashCode())); + albumArtIds.put(target, Math.abs(url.hashCode())); // re-send the cached DISPINFOTWO message, substituting in the new albumArtId - if (dispInfoCache.get(target.getId()) != null) { - connector.sendCommand(dispInfoCache.get(target.getId()).replace(ALBUM_ART_ID, - (OFFSET_ZERO + Integer.toHexString(albumArtIds.get(target.getId()))))); + if (dispInfoCache.get(target) != null) { + connector.sendCommand(dispInfoCache.get(target).replace(ALBUM_ART_ID, + (OFFSET_ZERO + Integer.toHexString(albumArtIds.get(target))))); } } else { - albumArtMap.put(target.getId(), NO_ART); - albumArtIds.put(target.getId(), 0); + albumArtMap.put(target, NO_ART); + albumArtIds.put(target, 0); updateChannelState(target, CHANNEL_ALBUM_ART, UNDEF); } } @@ -655,15 +678,16 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { logger.debug("onNewMessageEvent: zone {}, source {}, value {}", evt.getZone(), evt.getSrc(), evt.getValue()); lastEventReceived = System.currentTimeMillis(); - String type = evt.getType(); - String zoneId = evt.getZone(); - String srcId = evt.getSrc(); - String updateData = evt.getValue().trim(); + final NuvoEnum zone = !evt.getZone().isEmpty() ? NuvoEnum.valueOf(ZONE + evt.getZone()) : NuvoEnum.SYSTEM; + final NuvoEnum source = !evt.getSrc().isEmpty() ? NuvoEnum.valueOf(SOURCE + evt.getSrc()) : NuvoEnum.SYSTEM; + final String sourceZone = source.getId() + zone.getId(); + final String updateData = evt.getValue().trim(); + if (this.getThing().getStatus() != ThingStatus.ONLINE) { updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, this.versionString); } - switch (type) { + switch (evt.getType()) { case TYPE_VERSION: this.versionString = updateData; // Determine if we are a Grand Concerto or not @@ -691,8 +715,8 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { // Publish the ALLOFF event to all button channels for awareness in source rules updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, ZERO + COMMA + ALLOFF); - NuvoEnum.VALID_SOURCES.forEach(source -> { - updateChannelState(NuvoEnum.valueOf(source), CHANNEL_BUTTON_PRESS, ALLOFF); + NuvoEnum.VALID_SOURCES.forEach(src -> { + updateChannelState(src, CHANNEL_BUTTON_PRESS, ALLOFF); }); break; @@ -707,14 +731,13 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_PAGE, ONE.equals(updateData) ? ON : OFF); break; case TYPE_SOURCE_UPDATE: - logger.debug("Source update: Source: {} - Value: {}", srcId, updateData); - NuvoEnum targetSource = NuvoEnum.valueOf(SOURCE + srcId); + logger.debug("Source update: Source: {} - Value: {}", source.getNum(), updateData); if (updateData.contains(DISPLINE)) { // example: DISPLINE2,"Play My Song (Featuring Dee Ajayi)" Matcher matcher = DISP_PATTERN.matcher(updateData); if (matcher.find()) { - updateChannelState(targetSource, CHANNEL_DISPLAY_LINE + matcher.group(1), matcher.group(2)); + updateChannelState(source, CHANNEL_DISPLAY_LINE + matcher.group(1), matcher.group(2)); } else { logger.debug("no match on message: {}", updateData); } @@ -723,89 +746,86 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { // 6 places(tenths of a second)-> max 999,999 /10/60/60/24 = 1.15 days Matcher matcher = DISP_INFO_PATTERN.matcher(updateData); if (matcher.find()) { - updateChannelState(targetSource, CHANNEL_TRACK_LENGTH, matcher.group(1)); - updateChannelState(targetSource, CHANNEL_TRACK_POSITION, matcher.group(2)); - updateChannelState(targetSource, CHANNEL_PLAY_MODE, matcher.group(3)); + updateChannelState(source, CHANNEL_TRACK_LENGTH, matcher.group(1)); + updateChannelState(source, CHANNEL_TRACK_POSITION, matcher.group(2)); + updateChannelState(source, CHANNEL_PLAY_MODE, matcher.group(3)); } else { logger.debug("no match on message: {}", updateData); } } else if (updateData.contains(NAME_QUOTE)) { // example: NAME"Ipod" String name = updateData.split("\"")[1]; - sourceLabels.put(srcId, name); + sourceLabels.put(String.valueOf(source.getNum()), name); } break; case TYPE_ZONE_UPDATE: - logger.debug("Zone update: Zone: {} - Value: {}", zoneId, updateData); + logger.debug("Zone update: Zone: {} - Value: {}", zone.getNum(), updateData); // example : OFF // or: ON,SRC3,VOL63,DND0,LOCK0 // or: ON,SRC3,MUTE,DND0,LOCK0 - NuvoEnum targetZone = NuvoEnum.valueOf(ZONE + zoneId); - if (OFF.equals(updateData)) { - updateChannelState(targetZone, CHANNEL_TYPE_POWER, OFF); - updateChannelState(targetZone, CHANNEL_TYPE_SOURCE, UNDEF); + updateChannelState(zone, CHANNEL_TYPE_POWER, OFF); + updateChannelState(zone, CHANNEL_TYPE_SOURCE, UNDEF); } else { Matcher matcher = ZONE_PATTERN.matcher(updateData); if (matcher.find()) { - updateChannelState(targetZone, CHANNEL_TYPE_POWER, ON); - updateChannelState(targetZone, CHANNEL_TYPE_SOURCE, matcher.group(1)); + updateChannelState(zone, CHANNEL_TYPE_POWER, ON); + updateChannelState(zone, CHANNEL_TYPE_SOURCE, matcher.group(1)); // update the other group member's selected source - updateSrcForZoneGroup(targetZone, matcher.group(1)); + updateSrcForZoneGroup(zone, matcher.group(1)); if (MUTE.equals(matcher.group(2))) { - updateChannelState(targetZone, CHANNEL_TYPE_MUTE, ON); + updateChannelState(zone, CHANNEL_TYPE_MUTE, ON); } else { - updateChannelState(targetZone, CHANNEL_TYPE_MUTE, NuvoCommand.OFF.getValue()); - updateChannelState(targetZone, CHANNEL_TYPE_VOLUME, matcher.group(2).replace(VOL, BLANK)); + updateChannelState(zone, CHANNEL_TYPE_MUTE, NuvoCommand.OFF.getValue()); + updateChannelState(zone, CHANNEL_TYPE_VOLUME, matcher.group(2).replace(VOL, BLANK)); } - updateChannelState(targetZone, CHANNEL_TYPE_DND, ONE.equals(matcher.group(3)) ? ON : OFF); - updateChannelState(targetZone, CHANNEL_TYPE_LOCK, ONE.equals(matcher.group(4)) ? ON : OFF); + updateChannelState(zone, CHANNEL_TYPE_DND, ONE.equals(matcher.group(3)) ? ON : OFF); + updateChannelState(zone, CHANNEL_TYPE_LOCK, ONE.equals(matcher.group(4)) ? ON : OFF); } else { logger.debug("no match on message: {}", updateData); } } break; case TYPE_ZONE_SOURCE_BUTTON: - logger.debug("Source Button pressed: Source: {} - Button: {}", srcId, updateData); - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, updateData); - updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zoneId + COMMA + updateData); + logger.debug("Source Button pressed: Source: {} - Button: {}", source.getNum(), updateData); + updateChannelState(source, CHANNEL_BUTTON_PRESS, updateData); + updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zone.getNum() + COMMA + updateData); break; case TYPE_NN_BUTTON: String buttonAction = NuvoStatusCodes.BUTTON_CODE.get(updateData); if (buttonAction != null) { - logger.debug("NuvoNet Source Button pressed: Source: {} - Button: {}", srcId, buttonAction); - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, buttonAction); - updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zoneId + COMMA + buttonAction); + logger.debug("NuvoNet Source Button pressed: Source: {} - Button: {}", source.getNum(), + buttonAction); + updateChannelState(source, CHANNEL_BUTTON_PRESS, buttonAction); + updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zone.getNum() + COMMA + buttonAction); } else { - logger.debug("NuvoNet Source Button pressed: Source: {} - Unknown button code: {}", srcId, + logger.debug("NuvoNet Source Button pressed: Source: {} - Unknown button code: {}", source.getNum(), updateData); - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, updateData); - updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zoneId + COMMA + updateData); + updateChannelState(source, CHANNEL_BUTTON_PRESS, updateData); + updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zone.getNum() + COMMA + updateData); } break; case TYPE_NN_MENU_ITEM_SELECTED: // ignore this update unless openHAB is handling this source - if (nuvoNetSrcMap.get(srcId).equals(2)) { - String sourceZone = SRC_KEY + srcId + ZONE_KEY + zoneId; + if (nuvoNetSrcMap.get(source).equals(2)) { String[] updateDataSplit = updateData.split(COMMA); String menuId = updateDataSplit[0]; int menuItemIdx = Integer.parseInt(updateDataSplit[1]) - 1; boolean exitMenu = false; if ("0xFFFFFFFF".equals(menuId)) { - TopMenu topMenuItem = nuvoMenus.getSource().get(Integer.parseInt(srcId) - 1).getTopMenu() + TopMenu topMenuItem = nuvoMenus.getSource().get(source.getNum() - 1).getTopMenu() .get(menuItemIdx); - logger.debug("Top Menu item selected: Source: {} - Menu Item: {}", srcId, - topMenuItem.getText()); - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, + logger.debug("Top Menu item selected: Source: {} - Menu Item: {}", source.getNum(), topMenuItem.getText()); + updateChannelState(source, CHANNEL_BUTTON_PRESS, topMenuItem.getText()); updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, - zoneId + COMMA + topMenuItem.getText()); + zone.getNum() + COMMA + topMenuItem.getText()); List subMenuItems = topMenuItem.getItems(); @@ -829,16 +849,15 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { } } else { // a sub menu item was selected - TopMenu topMenuItem = nuvoMenus.getSource().get(Integer.parseInt(srcId) - 1).getTopMenu() + TopMenu topMenuItem = nuvoMenus.getSource().get(source.getNum() - 1).getTopMenu() .get(Integer.decode(menuId) - 11); String subMenuItem = topMenuItem.getItems().get(menuItemIdx); - logger.debug("Sub Menu item selected: Source: {} - Menu Item: {}", srcId, - topMenuItem.getText() + "|" + subMenuItem); - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, + logger.debug("Sub Menu item selected: Source: {} - Menu Item: {}", source.getNum(), topMenuItem.getText() + "|" + subMenuItem); + updateChannelState(source, CHANNEL_BUTTON_PRESS, topMenuItem.getText() + "|" + subMenuItem); updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, - zoneId + COMMA + topMenuItem.getText() + "|" + subMenuItem); + zone.getNum() + COMMA + topMenuItem.getText() + "|" + subMenuItem); exitMenu = true; } @@ -854,9 +873,8 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { break; case TYPE_NN_MENUREQ: // ignore this update unless openHAB is handling this source - if (nuvoNetSrcMap.get(srcId).equals(2)) { - logger.debug("Menu Request: Source: {} - Value: {}", srcId, updateData); - String sourceZone = SRC_KEY + srcId + ZONE_KEY + zoneId; + if (nuvoNetSrcMap.get(source).equals(2)) { + logger.debug("Menu Request: Source: {} - Value: {}", source.getNum(), updateData); // For now we only support one level deep menus. If second field is '1', indicates go back to main // menu. String[] menuDataSplit = updateData.split(COMMA); @@ -870,16 +888,14 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { } break; case TYPE_ZONE_CONFIG: - logger.debug("Zone Configuration: Zone: {} - Value: {}", zoneId, updateData); + logger.debug("Zone Configuration: Zone: {} - Value: {}", zone.getNum(), updateData); // example: BASS1,TREB-2,BALR2,LOUDCMP1 Matcher matcher = ZONE_CFG_EQ_PATTERN.matcher(updateData); if (matcher.find()) { - updateChannelState(NuvoEnum.valueOf(ZONE + zoneId), CHANNEL_TYPE_BASS, matcher.group(1)); - updateChannelState(NuvoEnum.valueOf(ZONE + zoneId), CHANNEL_TYPE_TREBLE, matcher.group(2)); - updateChannelState(NuvoEnum.valueOf(ZONE + zoneId), CHANNEL_TYPE_BALANCE, - NuvoStatusCodes.getBalanceFromStr(matcher.group(3))); - updateChannelState(NuvoEnum.valueOf(ZONE + zoneId), CHANNEL_TYPE_LOUDNESS, - ONE.equals(matcher.group(4)) ? ON : OFF); + updateChannelState(zone, CHANNEL_TYPE_BASS, matcher.group(1)); + updateChannelState(zone, CHANNEL_TYPE_TREBLE, matcher.group(2)); + updateChannelState(zone, CHANNEL_TYPE_BALANCE, NuvoStatusCodes.getBalanceFromStr(matcher.group(3))); + updateChannelState(zone, CHANNEL_TYPE_LOUDNESS, ONE.equals(matcher.group(4)) ? ON : OFF); } else { matcher = ZONE_CFG_PATTERN.matcher(updateData); // example: ENABLE1,NAME"Great Room",SLAVETO0,GROUP1,SOURCES63,XSRC0,IR1,DND0,LOCKED0,SLAVEEQ0 @@ -888,7 +904,7 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { // if this zone is a member of a group (1-4), add the zone's enum to the appropriate group map if (!ZERO.equals(matcher.group(3))) { - nuvoGroupMap.get(matcher.group(3)).add(NuvoEnum.valueOf(ZONE + zoneId)); + nuvoGroupMap.get(matcher.group(3)).add(zone); } } else { logger.debug("no match on message: {}", updateData); @@ -897,48 +913,47 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { break; case TYPE_NN_ALBUM_ART_REQ: // ignore this update unless openHAB is handling this source - if (nuvoNetSrcMap.get(srcId).equals(2)) { - logger.debug("Album Art Request for Source: {} - Data: {}", srcId, updateData); + if (nuvoNetSrcMap.get(source).equals(2)) { + logger.debug("Album Art Request for Source: {} - Data: {}", source.getNum(), updateData); // 0x620FD879,80,80,2,0x00C0C0C0,0,0,0,0,1 String[] albumArtReq = updateData.split(COMMA); - albumArtIds.put(SRC_KEY + srcId, Integer.decode(albumArtReq[0])); + albumArtIds.put(source, Integer.decode(albumArtReq[0])); try { - if (albumArtMap.get(SRC_KEY + srcId).length > 1) { - connector.sendCommand( - SRC_KEY + srcId + ALBUM_ART_AVAILABLE + albumArtIds.get(SRC_KEY + srcId) + COMMA - + albumArtMap.get(SRC_KEY + srcId).length); + if (albumArtMap.get(source).length > 1) { + connector.sendCommand(source.getId() + ALBUM_ART_AVAILABLE + albumArtIds.get(source) + COMMA + + albumArtMap.get(source).length); } else { - connector.sendCommand(SRC_KEY + srcId + ALBUM_ART_AVAILABLE + ZERO_COMMA); + connector.sendCommand(source.getId() + ALBUM_ART_AVAILABLE + ZERO_COMMA); } } catch (NuvoException e) { - logger.debug("Error sending ALBUMARTAVAILABLE command for source: {}", srcId); + logger.debug("Error sending ALBUMARTAVAILABLE command for source: {}", source.getNum()); } } break; case TYPE_NN_ALBUM_ART_FRAG_REQ: // ignore this update unless openHAB is handling this source - if (nuvoNetSrcMap.get(srcId).equals(2)) { - logger.debug("Album Art Fragment Request for Source: {} - Data: {}", srcId, updateData); + if (nuvoNetSrcMap.get(source).equals(2)) { + logger.debug("Album Art Fragment Request for Source: {} - Data: {}", source.getNum(), updateData); // 0x620FD879,0,750 (id, requested offset from start of image, byte length requested) String[] albumArtFragReq = updateData.split(COMMA); int requestedId = Integer.decode(albumArtFragReq[0]); int offset = Integer.parseInt(albumArtFragReq[1]); int length = Integer.parseInt(albumArtFragReq[2]); - if (requestedId == albumArtIds.get(SRC_KEY + srcId)) { + if (requestedId == albumArtIds.get(source)) { byte[] chunk = new byte[length]; - byte[] albumArtBytes = albumArtMap.get(SRC_KEY + srcId); + byte[] albumArtBytes = albumArtMap.get(source); if (albumArtBytes != null) { System.arraycopy(albumArtBytes, offset, chunk, 0, length); final String frag = Base64.getEncoder().encodeToString(chunk); try { - connector.sendCommand(SRC_KEY + srcId + ALBUM_ART_FRAG + requestedId + COMMA + offset + connector.sendCommand(source.getId() + ALBUM_ART_FRAG + requestedId + COMMA + offset + COMMA + frag.length() + COMMA + frag); } catch (NuvoException e) { - logger.debug("Error sending ALBUMARTFRAG command for source: {}, artId: {}", srcId, - requestedId); + logger.debug("Error sending ALBUMARTFRAG command for source: {}, artId: {}", + source.getNum(), requestedId); } } } @@ -946,19 +961,19 @@ public void onNewMessageEvent(NuvoMessageEvent evt) { break; case TYPE_NN_FAVORITE_REQ: // ignore this update unless openHAB is handling this source - if (nuvoNetSrcMap.get(srcId).equals(2)) { - logger.debug("Favorite request for source: {} - favoriteId: {}", srcId, updateData); + if (nuvoNetSrcMap.get(source).equals(2)) { + logger.debug("Favorite request for source: {} - favoriteId: {}", source.getNum(), updateData); try { int playlistIdx = Integer.parseInt(updateData, 16) - 1000; - updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, - "PLAY_MUSIC_PRESET:" + favoriteMap.get(srcId)[playlistIdx]); + updateChannelState(source, CHANNEL_BUTTON_PRESS, + PLAY_MUSIC_PRESET + favoriteMap.get(source)[playlistIdx]); } catch (NumberFormatException nfe) { logger.debug("Unable to parse favoriteId: {}", updateData); } } break; default: - logger.debug("onNewMessageEvent: unhandled event type {}", type); + logger.debug("onNewMessageEvent: unhandled event type {}", evt.getType()); // Return here because receiving an unknown message does not indicate that one can poll return; } @@ -1029,72 +1044,75 @@ private void enableNuvonet(boolean showReady) { } // enable NuvoNet for each source configured as an openHAB NuvoNet source - nuvoNetSrcMap.forEach((srcNum, val) -> { - if (val == 2) { + nuvoNetSrcMap.forEach((source, val) -> { + if (val.equals(2)) { try { - connector.sendCommand("SCFG" + srcNum + "NUVONET1"); + connector.sendCommand(source.getConfigId() + "NUVONET1"); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } catch (NuvoException | InterruptedException e) { - logger.debug("Error sending SCFG command for source: {}", srcNum); + logger.debug("Error sending SCFG command for source: {}", source.getNum()); } } }); try { // set '1' flag for each source configured as an MPS4 NuvoNet source or openHAB NuvoNet source - connector.sendCommand("SNUMBERS" + (nuvoNetSrcMap.get("1") > 0 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("2") > 0 ? ONE : ZERO) + COMMA + (nuvoNetSrcMap.get("3") > 0 ? ONE : ZERO) - + COMMA + (nuvoNetSrcMap.get("4") > 0 ? ONE : ZERO) + COMMA - + (nuvoNetSrcMap.get("5") > 0 ? ONE : ZERO) + COMMA + (nuvoNetSrcMap.get("6") > 0 ? ONE : ZERO)); + connector.sendCommand("SNUMBERS" + nuvoNetSrcMap.get(NuvoEnum.SOURCE1).compareTo(0) + COMMA + + nuvoNetSrcMap.get(NuvoEnum.SOURCE2).compareTo(0) + COMMA + + nuvoNetSrcMap.get(NuvoEnum.SOURCE3).compareTo(0) + COMMA + + nuvoNetSrcMap.get(NuvoEnum.SOURCE4).compareTo(0) + COMMA + + nuvoNetSrcMap.get(NuvoEnum.SOURCE5).compareTo(0) + COMMA + + nuvoNetSrcMap.get(NuvoEnum.SOURCE6).compareTo(0)); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } catch (NuvoException | InterruptedException e) { logger.debug("Error sending SNUMBERS command"); } // go though each source and if is openHAB NuvoNet then configure menu, favorites, etc. - nuvoNetSrcMap.forEach((srcNum, val) -> { - if (val == 2) { + nuvoNetSrcMap.forEach((source, val) -> { + if (val.equals(2)) { try { - List topMenuItems = nuvoMenus.getSource().get(Integer.parseInt(srcNum) - 1).getTopMenu(); + List topMenuItems = nuvoMenus.getSource().get(source.getNum() - 1).getTopMenu(); if (!topMenuItems.isEmpty()) { connector.sendCommand( - SRC_KEY + srcNum + "MENU," + (topMenuItems.size() < 10 ? topMenuItems.size() : 10)); + source.getId() + "MENU," + (topMenuItems.size() < 10 ? topMenuItems.size() : 10)); Thread.sleep(SLEEP_BETWEEN_CMD_MS); for (int i = 0; i < (topMenuItems.size() < 10 ? topMenuItems.size() : 10); i++) { - connector.sendCommand(SRC_KEY + srcNum + "MENUITEM" + (i + 1) + "," + connector.sendCommand(source.getId() + "MENUITEM" + (i + 1) + "," + (topMenuItems.get(i).getItems().isEmpty() ? ZERO : ONE) + ",0,\"" + topMenuItems.get(i).getText() + "\""); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } } - String[] favorites = favoriteMap.get(srcNum); + String[] favorites = favoriteMap.get(source); if (favorites != null) { - connector.sendCommand(SRC_KEY + srcNum + "FAVORITES" + connector.sendCommand(source.getId() + "FAVORITES" + (favorites.length < 20 ? favorites.length : 20) + COMMA - + ("1".equals(srcNum) ? ONE : ZERO) + COMMA + ("2".equals(srcNum) ? ONE : ZERO) + COMMA - + ("3".equals(srcNum) ? ONE : ZERO) + COMMA + ("4".equals(srcNum) ? ONE : ZERO) + COMMA - + ("5".equals(srcNum) ? ONE : ZERO) + COMMA + ("6".equals(srcNum) ? ONE : ZERO)); + + (source.getNum() == 1 ? ONE : ZERO) + COMMA + (source.getNum() == 2 ? ONE : ZERO) + + COMMA + (source.getNum() == 3 ? ONE : ZERO) + COMMA + + (source.getNum() == 4 ? ONE : ZERO) + COMMA + (source.getNum() == 5 ? ONE : ZERO) + + COMMA + (source.getNum() == 6 ? ONE : ZERO)); Thread.sleep(SLEEP_BETWEEN_CMD_MS); for (int i = 0; i < (favorites.length < 20 ? favorites.length : 20); i++) { - connector.sendCommand(SRC_KEY + srcNum + "FAVORITESITEM" + (i + 1000) + ",0,0,\"" - + favPrefixMap.get(srcNum) + favorites[i] + "\""); + connector.sendCommand(source.getId() + "FAVORITESITEM" + (i + 1000) + ",0,0,\"" + + favPrefixMap.get(source) + favorites[i] + "\""); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } } if (showReady) { - connector.sendCommand(SRC_KEY + srcNum + "DISPINFOTWO0,0,0,0,0,0,0"); + connector.sendCommand(source.getId() + "DISPINFOTWO0,0,0,0,0,0,0"); Thread.sleep(SLEEP_BETWEEN_CMD_MS); - connector.sendCommand(SRC_KEY + srcNum + "DISPLINES0,0,0,\"Ready\",\"\",\"\",\"\""); + connector.sendCommand(source.getId() + "DISPLINES0,0,0,\"Ready\",\"\",\"\",\"\""); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } } catch (NuvoException | InterruptedException e) { - logger.debug("Error configuring NuvoNet for source: {}", srcNum); + logger.debug("Error configuring NuvoNet for source: {}", source.getNum()); } } }); @@ -1161,11 +1179,11 @@ private void pollStatus() { NuvoEnum.VALID_SOURCES.forEach(source -> { try { - connector.sendQuery(NuvoEnum.valueOf(source), NuvoCommand.NAME); + connector.sendQuery(source, NuvoCommand.NAME); Thread.sleep(SLEEP_BETWEEN_CMD_MS); - connector.sendQuery(NuvoEnum.valueOf(source), NuvoCommand.DISPINFO); + connector.sendQuery(source, NuvoCommand.DISPINFO); Thread.sleep(SLEEP_BETWEEN_CMD_MS); - connector.sendQuery(NuvoEnum.valueOf(source), NuvoCommand.DISPLINE); + connector.sendQuery(source, NuvoCommand.DISPLINE); Thread.sleep(SLEEP_BETWEEN_CMD_MS); } catch (NuvoException | InterruptedException e) { logger.debug("Error Querying Source data: {}", e.getMessage());