diff --git a/bundles/org.openhab.binding.nuvo/README.md b/bundles/org.openhab.binding.nuvo/README.md
index 618b7b7ea..e4a407cd8 100644
--- a/bundles/org.openhab.binding.nuvo/README.md
+++ b/bundles/org.openhab.binding.nuvo/README.md
@@ -85,35 +85,36 @@ connection: &conNuvo
The following channels are available:
-| Channel ID | Item Type | Description |
-|--------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------|
-| system#alloff | Switch | Turn all zones off simultaneously |
-| system#allmute | Switch | Mute or unmute all zones simultaneously |
-| system#page | Switch | Turn on or off the Page All Zones feature (while on the amplifier switches to source 6) |
-| system#sendcmd | String | Send a command to the amplifier |
-| zoneN#power (where N= 1-20) | Switch | Turn the power for a zone on or off |
-| 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#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 |
-| zoneN#balance (where N= 1-20) | Number | Adjust the balance control for a zone (-18 to 18 [in increments of 2]) -18=left, 0=center, 18=right |
-| zoneN#loudness (where N= 1-20) | Switch | Turn on or off the loudness compensation setting for the zone |
-| zoneN#dnd (where N= 1-20) | Switch | Turn on or off the Do Not Disturb for the zone (for when the amplifier's Page All Zones feature is activated) |
-| zoneN#lock (where N= 1-20) | Contact | Indicates if this zone is currently locked |
-| zoneN#party (where N= 1-20) | Switch | Turn on or off the party mode feature with this zone as the host |
-| sourceN#display_line1 (where N= 1-6) | String | 1st line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
-| sourceN#display_line2 (where N= 1-6) | String | 2nd line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
-| sourceN#display_line3 (where N= 1-6) | String | 3rd line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
-| sourceN#display_line4 (where N= 1-6) | String | 4th line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
-| sourceN#play_mode (where N= 1-6) | String | The current playback mode of the source, ie: Playing, Paused, etc. (ReadOnly) See rules example for updating |
-| sourceN#track_length (where N= 1-6) | Number:Time | The total running time of the current playing track (ReadOnly) See rules example for updating |
-| sourceN#track_position (where N= 1-6)| Number:Time | The running time elapsed of the current playing track (ReadOnly) See rules example for updating |
-| sourceN#button_press (where N= 1-6) | String | Indicates the last button pressed on the keypad for a non NuvoNet source or openHAB NuvoNet source (ReadOnly) |
-| sourceN#art_url (where N= 1-6) | String | MPS4 Only! The URL of the Album Art JPG for this source that is displayed on a CTP-36. See *very advanced* rules (SendOnly) |
-| sourceN#album_art (where N= 1-6) | Image | The Album Art loaded from the art_url channel for display in a UI widget (ReadOnly) |
+| Channel ID | Item Type | Description |
+|--------------------------------------|-------------|--------------------------------------------------------------------------------------------------------------------------------|
+| system#alloff | Switch | Turn all zones off simultaneously |
+| system#allmute | Switch | Mute or unmute all zones simultaneously |
+| system#page | Switch | Turn on or off the Page All Zones feature (while on the amplifier switches to source 6) |
+| system#sendcmd | String | Send a command to the amplifier |
+| system#buttonpress | String | Indicates the zone number followed by a comma and the last button pressed or NuvoNet menu item selected on a keypad (ReadOnly) |
+| zoneN#power (where N= 1-20) | Switch | Turn the power for a zone on or off |
+| 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#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 |
+| zoneN#balance (where N= 1-20) | Number | Adjust the balance control for a zone (-18 to 18 [in increments of 2]) -18=left, 0=center, 18=right |
+| zoneN#loudness (where N= 1-20) | Switch | Turn on or off the loudness compensation setting for the zone |
+| zoneN#dnd (where N= 1-20) | Switch | Turn on or off the Do Not Disturb for the zone (for when the amplifier's Page All Zones feature is activated) |
+| zoneN#lock (where N= 1-20) | Contact | Indicates if this zone is currently locked |
+| zoneN#party (where N= 1-20) | Switch | Turn on or off the party mode feature with this zone as the host |
+| sourceN#display_line1 (where N= 1-6) | String | 1st line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
+| sourceN#display_line2 (where N= 1-6) | String | 2nd line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
+| sourceN#display_line3 (where N= 1-6) | String | 3rd line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
+| sourceN#display_line4 (where N= 1-6) | String | 4th line of text being displayed on the keypad. Can be updated for a non NuvoNet source |
+| sourceN#play_mode (where N= 1-6) | String | The current playback mode of the source, ie: Playing, Paused, etc. (ReadOnly) See rules example for updating |
+| sourceN#track_length (where N= 1-6) | Number:Time | The total running time of the current playing track (ReadOnly) See rules example for updating |
+| sourceN#track_position (where N= 1-6)| Number:Time | The running time elapsed of the current playing track (ReadOnly) See rules example for updating |
+| sourceN#button_press (where N= 1-6) | String | Indicates the last button pressed on the keypad for a non NuvoNet source or openHAB NuvoNet source (ReadOnly) |
+| sourceN#art_url (where N= 1-6) | String | MPS4 Only! The URL of the Album Art JPG for this source that is displayed on a CTP-36. See *very advanced* rules (SendOnly) |
+| sourceN#album_art (where N= 1-6) | Image | The Album Art loaded from the art_url channel for display in a UI widget (ReadOnly) |
## Full Example
@@ -139,6 +140,7 @@ Switch nuvo_system_alloff "All Zones Off" { channel="nuvo:amplifier:myamp:system
Switch nuvo_system_allmute "All Zones Mute" { channel="nuvo:amplifier:myamp:system#allmute" }
Switch nuvo_system_page "Page All Zones" { channel="nuvo:amplifier:myamp:system#page" }
String nuvo_system_sendcmd "Send Command" { channel="nuvo:amplifier:myamp:system#sendcmd" }
+String nuvo_system_buttonpress "Zone Button: [%s]" { channel="nuvo:amplifier:myamp:system#buttonpress" }
// zones
Switch nuvo_z1_power "Power" { channel="nuvo:amplifier:myamp:zone1#power" }
@@ -473,12 +475,57 @@ A complete XML string for the desired menu is then stored in the `menuXmlSrcN` c
menu3 xmenu3 y
+
```
When a menu item is selected, the text of the topmenu item and sub menu item (if applicable) will be sent to the button channel in a pipe delimited format.
For example, when item `menu1 b` is selected, the text `Top menu 1|menu1 b` will be sent to the button channel.
When the item `Top menu 2` is selected the text sent to the button channel will simply be `Top menu 2` since this menu item does not have any sub menu items.
+### Rule to trigger an action based on which keypad zone where a button was pressed or menu item selected
+
+By using the `system#buttonpress` channel it is possible to trigger an action based on which keypad zone was used to send the action.
+This channel appends the zone number and a comma before the button action or menu item selection.
+
+For example if the Play/Pause button is pressed on Zone 7, the channel will display: `7,PLAYPAUSE`
+Also if a menu item from a custom menu was selected, ie: `Top menu 1` on Zone 5, the channel will display: `5,Top menu 1`
+
+The functionality can be used to create very powerful rules as demontrated below. The following rule triggered from a menu item turns off all zones except for the zone that triggered the rule.
+
+nuvo-turn-off-all-but-caller.rules:
+
+```
+rule "Turn off all zones except caller zone"
+when
+ Item nuvo_system_buttonpress received update
+then
+ var callerZone = newState.toString().split(",").get(0)
+ var button = newState.toString().split(",").get(1)
+
+ if (button == "Turn off other zones") {
+ if (callerZone != "1") {
+ nuvo_z1_power.sendCommand(OFF)
+ }
+ if (callerZone != "2") {
+ nuvo_z2_power.sendCommand(OFF)
+ }
+ if (callerZone != "3") {
+ nuvo_z3_power.sendCommand(OFF)
+ }
+ if (callerZone != "4") {
+ nuvo_z4_power.sendCommand(OFF)
+ }
+ if (callerZone != "5") {
+ nuvo_z5_power.sendCommand(OFF)
+ }
+ if (callerZone != "6") {
+ nuvo_z6_power.sendCommand(OFF)
+ }
+ }
+end
+
+```
+
### MPS4 openHAB NuvoNet source custom integration rules *(very advanced)*
The following are a set of example rules necessary to integrate metadata and control of another openHAB connected source (ie: Chromecast) into an openHAB NuvoNet source.
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 c3cf2497c..d65fceda0 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
@@ -35,6 +35,7 @@ public class NuvoBindingConstants {
public static final String CHANNEL_TYPE_ALLMUTE = "allmute";
public static final String CHANNEL_TYPE_PAGE = "page";
public static final String CHANNEL_TYPE_SENDCMD = "sendcmd";
+ public static final String CHANNEL_TYPE_BUTTONPRESS = "buttonpress";
// zone
public static final String CHANNEL_TYPE_POWER = "power";
@@ -71,14 +72,14 @@ public class NuvoBindingConstants {
public static final String TYPE_PAGE = "page";
public static final String TYPE_SOURCE_UPDATE = "source_update";
public static final String TYPE_ZONE_UPDATE = "zone_update";
- public static final String TYPE_ZONE_BUTTON = "zone_button";
- public static final String TYPE_ZONE_BUTTON2 = "zone_button2";
- public static final String TYPE_ZONE_MENUREQ = "zone_menureq";
- public static final String TYPE_MENU_ITEM_SELECTED = "top_menu_button";
public static final String TYPE_ZONE_CONFIG = "zone_config";
- public static final String TYPE_ALBUM_ART_REQ = "album_art_req";
- public static final String TYPE_ALBUM_ART_FRAG_REQ = "album_art_frag_req";
- public static final String TYPE_FAVORITE_REQ = "favorite_req";
+ public static final String TYPE_ZONE_SOURCE_BUTTON = "zone_source_button";
+ public static final String TYPE_NN_BUTTON = "nn_button";
+ public static final String TYPE_NN_MENUREQ = "nn_menureq";
+ public static final String TYPE_NN_MENU_ITEM_SELECTED = "nn_menu_item_selected";
+ public static final String TYPE_NN_ALBUM_ART_REQ = "nn_album_art_req";
+ public static final String TYPE_NN_ALBUM_ART_FRAG_REQ = "nn_album_art_frag_req";
+ public static final String TYPE_NN_FAVORITE_REQ = "nn_favorite_req";
// misc
public static final String ON = "ON";
diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java
index bb084ffd7..c3321eb3c 100644
--- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java
+++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java
@@ -54,21 +54,21 @@ public abstract class NuvoConnector {
private static final Pattern SRC_PATTERN = Pattern.compile("^#S(\\d{1})(.*)$");
private static final Pattern ZONE_PATTERN = Pattern.compile("^#Z(\\d{1,2}),(.*)$");
- private static final Pattern ZONE_BUTTON_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})(.*)$");
- private static final Pattern ZONE_MENUREQ_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})MENUREQ(.*)$");
- private static final Pattern ZONE_BUTTON2_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})BUTTON(.*)$");
- private static final Pattern ZONE_BUTTONTWO_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})BUTTONTWO(.*)$");
+ private static final Pattern ZONE_SOURCE_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})(.*)$");
+ private static final Pattern NN_MENUREQ_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})MENUREQ(.*)$");
+ private static final Pattern NN_BUTTON_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})BUTTON(.*)$");
+ private static final Pattern NN_BUTTONTWO_PATTERN = Pattern.compile("^#Z(\\d{1,2})S(\\d{1})BUTTONTWO(.*)$");
private static final Pattern ZONE_CFG_PATTERN = Pattern.compile("^#ZCFG(\\d{1,2}),(.*)$");
// S2ALBUMARTREQ0x620FD879,80,80,2,0x00C0C0C0,0,0,0,0,1
- private static final Pattern ALBUM_ART_REQ = Pattern.compile("^#S(\\d{1})ALBUMARTREQ(.*)$");
+ private static final Pattern NN_ALBUM_ART_REQ = Pattern.compile("^#S(\\d{1})ALBUMARTREQ(.*)$");
// S2ALBUMARTFRAGREQ0x620FD879,0,750
- private static final Pattern ALBUM_ART_FRAG_REQ = Pattern.compile("^#S(\\d{1})ALBUMARTFRAGREQ(.*)$");
+ private static final Pattern NN_ALBUM_ART_FRAG_REQ = Pattern.compile("^#S(\\d{1})ALBUMARTFRAGREQ(.*)$");
// S6FAVORITE0x000003E8
- private static final Pattern FAVORITE_PATTERN = Pattern.compile("^#S(\\d{1})FAVORITE0x(.*)$");
+ private static final Pattern NN_FAVORITE_PATTERN = Pattern.compile("^#S(\\d{1})FAVORITE0x(.*)$");
private final Logger logger = LoggerFactory.getLogger(NuvoConnector.class);
@@ -88,6 +88,7 @@ public abstract class NuvoConnector {
private List listeners = new ArrayList<>();
private boolean isEssentia = true;
+ private boolean isAnyOhNuvoNet = false;
/**
* Get whether the connection is established or not
@@ -116,6 +117,15 @@ public abstract class NuvoConnector {
this.isEssentia = isEssentia;
}
+ /**
+ * Tell the connector to listen for NuvoNet source messages
+ *
+ * @param true if any sources are configured as openHAB NuvoNet sources
+ */
+ public void setAnyOhNuvoNet(boolean isAnyOhNuvoNet) {
+ this.isAnyOhNuvoNet = isAnyOhNuvoNet;
+ }
+
/**
* Set the thread that handles the feedback messages
*
@@ -307,7 +317,7 @@ public abstract class NuvoConnector {
}
/**
- * Analyze an incoming message and dispatch corresponding (type, key, value) to the event listeners
+ * Analyze an incoming message and dispatch corresponding (type, zone, src, value) to the event listeners
*
* @param incomingMessage the received message
*/
@@ -327,119 +337,117 @@ public abstract class NuvoConnector {
} catch (NuvoException e) {
logger.debug("Error sending response to PING command");
}
- dispatchKeyValue(TYPE_PING, BLANK, BLANK);
+ dispatchKeyValue(TYPE_PING, BLANK);
return;
}
if (RESTART.equals(message)) {
- dispatchKeyValue(TYPE_RESTART, BLANK, BLANK);
+ dispatchKeyValue(TYPE_RESTART, BLANK);
return;
}
if (message.contains(VER_STR_E6) || message.contains(VER_STR_GC)) {
// example: #VER"NV-E6G FWv2.66 HWv0"
// split on " and return the version number
- dispatchKeyValue(TYPE_VERSION, "", message.split("\"")[1]);
+ dispatchKeyValue(TYPE_VERSION, message.split("\"")[1]);
return;
}
if (message.equals(ALL_OFF)) {
- dispatchKeyValue(TYPE_ALLOFF, BLANK, BLANK);
+ dispatchKeyValue(TYPE_ALLOFF, BLANK);
return;
}
if (message.contains(MUTE)) {
- dispatchKeyValue(TYPE_ALLMUTE, BLANK, message.substring(message.length() - 1));
+ dispatchKeyValue(TYPE_ALLMUTE, message.substring(message.length() - 1));
return;
}
if (message.contains(PAGE)) {
- dispatchKeyValue(TYPE_PAGE, BLANK, message.substring(message.length() - 1));
+ dispatchKeyValue(TYPE_PAGE, message.substring(message.length() - 1));
return;
}
- // Amp controller sent an album art request
- Matcher matcher = ALBUM_ART_REQ.matcher(message);
- if (matcher.find()) {
- // pull out the source id and the remainder of the message
- dispatchKeyValue(TYPE_ALBUM_ART_REQ, matcher.group(1), matcher.group(2));
- return;
- }
+ Matcher matcher;
- // Amp controller sent an album art fragment request
- matcher = ALBUM_ART_FRAG_REQ.matcher(message);
- if (matcher.find()) {
- // pull out the source id and the remainder of the message
- dispatchKeyValue(TYPE_ALBUM_ART_FRAG_REQ, matcher.group(1), matcher.group(2));
- return;
- }
+ if (isAnyOhNuvoNet) {
+ // Amp controller sent a NuvoNet album art request
+ matcher = NN_ALBUM_ART_REQ.matcher(message);
+ if (matcher.find()) {
+ dispatchKeyValue(TYPE_NN_ALBUM_ART_REQ, BLANK, matcher.group(1), matcher.group(2));
+ return;
+ }
- // Amp controller sent a request to play a favorite
- matcher = FAVORITE_PATTERN.matcher(message);
- if (matcher.find()) {
- // pull out the source id and the remainder of the message
- dispatchKeyValue(TYPE_FAVORITE_REQ, matcher.group(1), matcher.group(2));
- return;
+ // Amp controller sent a NuvoNet album art fragment request
+ matcher = NN_ALBUM_ART_FRAG_REQ.matcher(message);
+ if (matcher.find()) {
+ dispatchKeyValue(TYPE_NN_ALBUM_ART_FRAG_REQ, BLANK, matcher.group(1), matcher.group(2));
+ return;
+ }
+
+ // Amp controller sent a request for a NuvoNet source to play a favorite
+ matcher = NN_FAVORITE_PATTERN.matcher(message);
+ if (matcher.find()) {
+ dispatchKeyValue(TYPE_NN_FAVORITE_REQ, BLANK, matcher.group(1), matcher.group(2));
+ return;
+ }
}
// Amp controller sent a source update ie: #S2DISPINFO,DUR3380,POS3090,STATUS2
// or #S2DISPLINE1,"1 of 17"
matcher = SRC_PATTERN.matcher(message);
if (matcher.find()) {
- // pull out the source id and the remainder of the message
- dispatchKeyValue(TYPE_SOURCE_UPDATE, matcher.group(1), matcher.group(2));
+ dispatchKeyValue(TYPE_SOURCE_UPDATE, BLANK, matcher.group(1), matcher.group(2));
return;
}
// Amp controller sent a zone update ie: #Z11,ON,SRC3,VOL63,DND0,LOCK0
matcher = ZONE_PATTERN.matcher(message);
if (matcher.find()) {
- // pull out the zone id and the remainder of the message
- dispatchKeyValue(TYPE_ZONE_UPDATE, matcher.group(1), matcher.group(2));
+ dispatchKeyValue(TYPE_ZONE_UPDATE, matcher.group(1), BLANK, matcher.group(2));
return;
}
- // Amp controller sent a zone BUTTONTWO press event ie: #Z11S3BUTTONTWO4,2,0,0,0
- matcher = ZONE_BUTTONTWO_PATTERN.matcher(message);
- if (matcher.find()) {
- // redundant - ignore
- return;
- }
-
- // Amp controller sent a zone BUTTON press event ie: #Z4S6BUTTON1,1,0xFFFFFFFF,1,3
- matcher = ZONE_BUTTON2_PATTERN.matcher(message);
- if (matcher.find()) {
- // pull out the remainder of the message: button #, action, menuid, itemid, itemidx
- String[] buttonSplit = matcher.group(3).split(COMMA);
-
- // second field is button action, only send DOWNUP (0) or DOWN (1), ignore UP (2)
- if (ZERO.equals(buttonSplit[1]) || ONE.equals(buttonSplit[1])) {
- // a button in a menu was pressed, send SxZy,menuid,itemidx
- if (!ZERO.equals(buttonSplit[2])) {
- dispatchKeyValue(TYPE_MENU_ITEM_SELECTED, matcher.group(2), SRC_KEY + matcher.group(2) + ZONE_KEY
- + matcher.group(1) + COMMA + buttonSplit[2] + COMMA + buttonSplit[3]);
- } else {
- // send the button # in the event, don't send extra fields menuid, itemid, etc..
- dispatchKeyValue(TYPE_ZONE_BUTTON2, matcher.group(2), buttonSplit[0]);
- }
+ if (isAnyOhNuvoNet) {
+ // Amp controller sent a NuvoNet zone/source BUTTONTWO press event ie: #Z11S3BUTTONTWO4,2,0,0,0
+ matcher = NN_BUTTONTWO_PATTERN.matcher(message);
+ if (matcher.find()) {
+ // redundant - ignore
+ return;
+ }
+
+ // Amp controller sent a NuvoNet zone/source BUTTON press event ie: #Z4S6BUTTON1,1,0xFFFFFFFF,1,3
+ matcher = NN_BUTTON_PATTERN.matcher(message);
+ if (matcher.find()) {
+ // pull out the remainder of the message: button #, action, menuid, itemid, itemidx
+ String[] buttonSplit = matcher.group(3).split(COMMA);
+
+ // second field is button action, only send DOWNUP (0) or DOWN (1), ignore UP (2)
+ if (ZERO.equals(buttonSplit[1]) || ONE.equals(buttonSplit[1])) {
+ // a button in a menu was pressed, send 'menuid,itemidx'
+ if (!ZERO.equals(buttonSplit[2])) {
+ dispatchKeyValue(TYPE_NN_MENU_ITEM_SELECTED, matcher.group(1), matcher.group(2),
+ buttonSplit[2] + COMMA + buttonSplit[3]);
+ } else {
+ // send the button # in the event, don't send extra fields menuid, itemid, etc..
+ dispatchKeyValue(TYPE_NN_BUTTON, matcher.group(1), matcher.group(2), buttonSplit[0]);
+ }
+ }
+ return;
+ }
+
+ // Amp controller sent a NuvoNet zone/source menu request event ie: #Z2S6MENUREQ0x0000000B,1,0,0
+ matcher = NN_MENUREQ_PATTERN.matcher(message);
+ if (matcher.find()) {
+ dispatchKeyValue(TYPE_NN_MENUREQ, matcher.group(1), matcher.group(2), matcher.group(3));
+ return;
}
- return;
}
- // Amp controller sent a menu request event ie: #Z2S6MENUREQ0x0000000B,1,0,0
- matcher = ZONE_MENUREQ_PATTERN.matcher(message);
+ // Amp controller sent a zone/source button press event ie: #Z11S3PLAYPAUSE
+ matcher = ZONE_SOURCE_PATTERN.matcher(message);
if (matcher.find()) {
- // pull out the source id and send SxZy plus the remainder of the message
- dispatchKeyValue(TYPE_ZONE_MENUREQ, matcher.group(2),
- SRC_KEY + matcher.group(2) + ZONE_KEY + matcher.group(1) + COMMA + matcher.group(3));
- return;
- }
-
- // Amp controller sent a zone button press event ie: #Z11S3PLAYPAUSE
- matcher = ZONE_BUTTON_PATTERN.matcher(message);
- if (matcher.find()) {
- // pull out the source id and the remainder of the message, ignore the zone id
- dispatchKeyValue(TYPE_ZONE_BUTTON, matcher.group(2), matcher.group(3));
+ dispatchKeyValue(TYPE_ZONE_SOURCE_BUTTON, matcher.group(1), matcher.group(2), matcher.group(3));
return;
}
@@ -447,7 +455,7 @@ public abstract class NuvoConnector {
matcher = ZONE_CFG_PATTERN.matcher(message);
if (matcher.find()) {
// pull out the zone id and the remainder of the message
- dispatchKeyValue(TYPE_ZONE_CONFIG, matcher.group(1), matcher.group(2));
+ dispatchKeyValue(TYPE_ZONE_CONFIG, matcher.group(1), BLANK, matcher.group(2));
return;
}
@@ -455,14 +463,25 @@ public abstract class NuvoConnector {
}
/**
- * Dispatch an event (type, key, value) to the event listeners
+ * Dispatch a system level event without zone or src to the event listeners
*
* @param type the type
- * @param key the key
* @param value the value
*/
- private void dispatchKeyValue(String type, String key, String value) {
- NuvoMessageEvent event = new NuvoMessageEvent(this, type, key, value);
+ private void dispatchKeyValue(String type, String value) {
+ dispatchKeyValue(type, BLANK, BLANK, value);
+ }
+
+ /**
+ * Dispatch an event (type, zone, src, value) to the event listeners
+ *
+ * @param type the type
+ * @param zone the zone id
+ * @param src the source id
+ * @param value the value
+ */
+ private void dispatchKeyValue(String type, String zone, String src, String value) {
+ NuvoMessageEvent event = new NuvoMessageEvent(this, type, zone, src, value);
listeners.forEach(l -> l.onNewMessageEvent(event));
}
}
diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoMessageEvent.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoMessageEvent.java
index 7539c941b..2e6cd59ae 100644
--- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoMessageEvent.java
+++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoMessageEvent.java
@@ -25,13 +25,15 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
public class NuvoMessageEvent extends EventObject {
private static final long serialVersionUID = 1L;
private final String type;
- private final String key;
+ private final String zone;
+ private final String src;
private final String value;
- public NuvoMessageEvent(Object source, String type, String key, String value) {
+ public NuvoMessageEvent(Object source, String type, String zone, String src, String value) {
super(source);
this.type = type;
- this.key = key;
+ this.zone = zone;
+ this.src = src;
this.value = value;
}
@@ -39,8 +41,12 @@ public class NuvoMessageEvent extends EventObject {
return type;
}
- public String getKey() {
- return key;
+ public String getZone() {
+ return zone;
+ }
+
+ public String getSrc() {
+ return src;
}
public String getValue() {
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 56320cb5c..bfa27e083 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
@@ -215,7 +215,7 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
if (serialPort != null && !serialPort.isEmpty()) {
connector = new NuvoSerialConnector(serialPortManager, serialPort, uid);
- } else if (port != null) {
+ } else if (host != null && port != null) {
connector = new NuvoIpConnector(host, port, uid);
this.isMps4 = (port.intValue() == MPS4_PORT);
} else {
@@ -239,6 +239,7 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
if (this.isAnyOhNuvoNet) {
logger.debug("At least one source is configured as an openHAB NuvoNet source");
+ connector.setAnyOhNuvoNet(true);
loadMenuConfiguration(config);
favoriteMap.put("1",
@@ -640,11 +641,12 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
*/
@Override
public void onNewMessageEvent(NuvoMessageEvent evt) {
- logger.debug("onNewMessageEvent: key {} = {}", evt.getKey(), evt.getValue());
+ logger.debug("onNewMessageEvent: zone {}, source {}, value {}", evt.getZone(), evt.getSrc(), evt.getValue());
lastEventReceived = System.currentTimeMillis();
String type = evt.getType();
- String key = evt.getKey();
+ String zoneId = evt.getZone();
+ String srcId = evt.getSrc();
String updateData = evt.getValue().trim();
if (this.getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, this.versionString);
@@ -687,8 +689,8 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_PAGE, ONE.equals(updateData) ? ON : OFF);
break;
case TYPE_SOURCE_UPDATE:
- logger.debug("Source update: Source: {} - Value: {}", key, updateData);
- NuvoEnum targetSource = NuvoEnum.valueOf(SOURCE + key);
+ logger.debug("Source update: Source: {} - Value: {}", srcId, updateData);
+ NuvoEnum targetSource = NuvoEnum.valueOf(SOURCE + srcId);
if (updateData.contains(DISPLINE)) {
// example: DISPLINE2,"Play My Song (Featuring Dee Ajayi)"
@@ -712,16 +714,16 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
} else if (updateData.contains(NAME_QUOTE)) {
// example: NAME"Ipod"
String name = updateData.split("\"")[1];
- sourceLabels.put(key, name);
+ sourceLabels.put(srcId, name);
}
break;
case TYPE_ZONE_UPDATE:
- logger.debug("Zone update: Zone: {} - Value: {}", key, updateData);
+ logger.debug("Zone update: Zone: {} - Value: {}", zoneId, updateData);
// example : OFF
// or: ON,SRC3,VOL63,DND0,LOCK0
// or: ON,SRC3,MUTE,DND0,LOCK0
- NuvoEnum targetZone = NuvoEnum.valueOf(ZONE + key);
+ NuvoEnum targetZone = NuvoEnum.valueOf(ZONE + zoneId);
if (OFF.equals(updateData)) {
updateChannelState(targetZone, CHANNEL_TYPE_POWER, OFF);
@@ -746,35 +748,43 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
}
}
break;
- case TYPE_ZONE_BUTTON:
- logger.debug("Zone Button pressed: Source: {} - Button: {}", key, updateData);
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS, updateData);
+ 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);
break;
- case TYPE_ZONE_BUTTON2:
+ case TYPE_NN_BUTTON:
String buttonAction = NuvoStatusCodes.BUTTON_CODE.get(updateData);
if (buttonAction != null) {
- logger.debug("Zone NuvoNet Button pressed: Source: {} - Button: {}", key, buttonAction);
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS, buttonAction);
+ 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);
} else {
- logger.debug("Zone NuvoNet Button pressed: Source: {} - Unknown button code: {}", key, updateData);
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS, updateData);
+ logger.debug("NuvoNet Source Button pressed: Source: {} - Unknown button code: {}", srcId,
+ updateData);
+ updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS, updateData);
+ updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS, zoneId + COMMA + updateData);
}
break;
- case TYPE_MENU_ITEM_SELECTED:
+ case TYPE_NN_MENU_ITEM_SELECTED:
// ignore this update unless openHAB is handling this source
- if (nuvoNetSrcMap.get(key).equals(2)) {
+ if (nuvoNetSrcMap.get(srcId).equals(2)) {
+ String sourceZone = SRC_KEY + srcId + ZONE_KEY + zoneId;
String[] updateDataSplit = updateData.split(COMMA);
- String zoneSource = updateDataSplit[0];
- String menuId = updateDataSplit[1];
- int menuItemIdx = Integer.parseInt(updateDataSplit[2]) - 1;
+ 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(key) - 1).getTopMenu()
+ TopMenu topMenuItem = nuvoMenus.getSource().get(Integer.parseInt(srcId) - 1).getTopMenu()
.get(menuItemIdx);
- logger.debug("Top Menu item selected: Source: {} - Menu Item: {}", key, topMenuItem.getText());
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS, topMenuItem.getText());
+ logger.debug("Top Menu item selected: Source: {} - Menu Item: {}", srcId,
+ topMenuItem.getText());
+ updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS,
+ topMenuItem.getText());
+ updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS,
+ zoneId + COMMA + topMenuItem.getText());
List subMenuItems = topMenuItem.getItems();
@@ -784,135 +794,139 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis
// send submenu (maximum of 20 items)
int subMenuSize = subMenuItems.size() < 20 ? subMenuItems.size() : 20;
try {
- connector.sendCommand(zoneSource + "MENU" + (menuItemIdx + 11) + ",0,0," + subMenuSize
+ connector.sendCommand(sourceZone + "MENU" + (menuItemIdx + 11) + ",0,0," + subMenuSize
+ ",0,0," + subMenuSize + ",\"" + topMenuItem.getText() + "\"");
Thread.sleep(SLEEP_BETWEEN_CMD_MS);
for (int i = 0; i < subMenuSize; i++) {
connector.sendCommand(
- zoneSource + "MENUITEM" + (i + 1) + ",0,0,\"" + subMenuItems.get(i) + "\"");
+ sourceZone + "MENUITEM" + (i + 1) + ",0,0,\"" + subMenuItems.get(i) + "\"");
}
} catch (NuvoException | InterruptedException e) {
- logger.debug("Error sending sub menu for {}", zoneSource);
+ logger.debug("Error sending sub menu to {}", sourceZone);
}
}
} else {
// a sub menu item was selected
- TopMenu topMenuItem = nuvoMenus.getSource().get(Integer.parseInt(key) - 1).getTopMenu()
+ TopMenu topMenuItem = nuvoMenus.getSource().get(Integer.parseInt(srcId) - 1).getTopMenu()
.get(Integer.decode(menuId) - 11);
String subMenuItem = topMenuItem.getItems().get(menuItemIdx);
- logger.debug("Sub Menu item selected: Source: {} - Menu Item: {}", key,
+ logger.debug("Sub Menu item selected: Source: {} - Menu Item: {}", srcId,
topMenuItem.getText() + "|" + subMenuItem);
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS,
+ updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS,
topMenuItem.getText() + "|" + subMenuItem);
+ updateChannelState(NuvoEnum.SYSTEM, CHANNEL_TYPE_BUTTONPRESS,
+ zoneId + COMMA + topMenuItem.getText() + "|" + subMenuItem);
exitMenu = true;
}
if (exitMenu) {
try {
// tell the zone to exit the menu
- connector.sendCommand(zoneSource + "MENU0,0,0,0,0,0,0,\"\"");
+ connector.sendCommand(sourceZone + "MENU0,0,0,0,0,0,0,\"\"");
} catch (NuvoException e) {
- logger.debug("Error sending exit menu command for {}", zoneSource);
+ logger.debug("Error sending exit menu command to {}", sourceZone);
}
}
}
break;
- case TYPE_ZONE_MENUREQ:
+ case TYPE_NN_MENUREQ:
// ignore this update unless openHAB is handling this source
- if (nuvoNetSrcMap.get(key).equals(2)) {
- logger.debug("Menu Request: Source: {} - Value: {}", key, updateData);
- // For now we only support one level deep menus. If third field is '1', indicates go back to main
+ if (nuvoNetSrcMap.get(srcId).equals(2)) {
+ logger.debug("Menu Request: Source: {} - Value: {}", srcId, updateData);
+ String sourceZone = SRC_KEY + srcId + ZONE_KEY + zoneId;
+ // For now we only support one level deep menus. If second field is '1', indicates go back to main
// menu.
- String[] menuDataSplit = updateData.split(",");
- if (menuDataSplit.length > 3 && ONE.equals(menuDataSplit[2])) {
+ String[] menuDataSplit = updateData.split(COMMA);
+ if (menuDataSplit.length > 2 && ONE.equals(menuDataSplit[1])) {
try {
- connector.sendCommand(menuDataSplit[0] + "MENU0xFFFFFFFF,0,0,0,0,0,0,\"\"");
+ connector.sendCommand(sourceZone + "MENU0xFFFFFFFF,0,0,0,0,0,0,\"\"");
} catch (NuvoException e) {
- logger.debug("Error sending main menu command for {}", menuDataSplit[0]);
+ logger.debug("Error sending main menu command to {}", sourceZone);
}
}
}
break;
case TYPE_ZONE_CONFIG:
- logger.debug("Zone Configuration: Zone: {} - Value: {}", key, updateData);
+ logger.debug("Zone Configuration: Zone: {} - Value: {}", zoneId, updateData);
// example: BASS1,TREB-2,BALR2,LOUDCMP1
Matcher matcher = ZONE_CFG_PATTERN.matcher(updateData);
if (matcher.find()) {
- updateChannelState(NuvoEnum.valueOf(ZONE + key), CHANNEL_TYPE_BASS, matcher.group(1));
- updateChannelState(NuvoEnum.valueOf(ZONE + key), CHANNEL_TYPE_TREBLE, matcher.group(2));
- updateChannelState(NuvoEnum.valueOf(ZONE + key), CHANNEL_TYPE_BALANCE,
+ 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 + key), CHANNEL_TYPE_LOUDNESS,
+ updateChannelState(NuvoEnum.valueOf(ZONE + zoneId), CHANNEL_TYPE_LOUDNESS,
ONE.equals(matcher.group(4)) ? ON : OFF);
} else {
logger.debug("no match on message: {}", updateData);
}
break;
- case TYPE_ALBUM_ART_REQ:
+ case TYPE_NN_ALBUM_ART_REQ:
// ignore this update unless openHAB is handling this source
- if (nuvoNetSrcMap.get(key).equals(2)) {
- logger.debug("Album Art Request for Source: {} - Data: {}", key, updateData);
+ if (nuvoNetSrcMap.get(srcId).equals(2)) {
+ logger.debug("Album Art Request for Source: {} - Data: {}", srcId, updateData);
// 0x620FD879,80,80,2,0x00C0C0C0,0,0,0,0,1
String[] albumArtReq = updateData.split(COMMA);
- albumArtIds.put(SRC_KEY + key, Integer.decode(albumArtReq[0]));
+ albumArtIds.put(SRC_KEY + srcId, Integer.decode(albumArtReq[0]));
try {
- if (albumArtMap.get(SRC_KEY + key).length > 1) {
- connector.sendCommand(SRC_KEY + key + ALBUM_ART_AVAILABLE + albumArtIds.get(SRC_KEY + key)
- + COMMA + albumArtMap.get(SRC_KEY + key).length);
+ 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);
} else {
- connector.sendCommand(SRC_KEY + key + ALBUM_ART_AVAILABLE + ZERO_COMMA);
+ connector.sendCommand(SRC_KEY + srcId + ALBUM_ART_AVAILABLE + ZERO_COMMA);
}
} catch (NuvoException e) {
- logger.debug("Error sending ALBUMARTAVAILABLE command for source: {}", key);
+ logger.debug("Error sending ALBUMARTAVAILABLE command for source: {}", srcId);
}
}
break;
- case TYPE_ALBUM_ART_FRAG_REQ:
+ case TYPE_NN_ALBUM_ART_FRAG_REQ:
// ignore this update unless openHAB is handling this source
- if (nuvoNetSrcMap.get(key).equals(2)) {
- logger.debug("Album Art Fragment Request for Source: {} - Data: {}", key, updateData);
+ if (nuvoNetSrcMap.get(srcId).equals(2)) {
+ logger.debug("Album Art Fragment Request for Source: {} - Data: {}", srcId, 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 + key)) {
+ if (requestedId == albumArtIds.get(SRC_KEY + srcId)) {
byte[] chunk = new byte[length];
- byte[] albumArtBytes = albumArtMap.get(SRC_KEY + key);
+ byte[] albumArtBytes = albumArtMap.get(SRC_KEY + srcId);
if (albumArtBytes != null) {
System.arraycopy(albumArtBytes, offset, chunk, 0, length);
final String frag = Base64.getEncoder().encodeToString(chunk);
try {
- connector.sendCommand(SRC_KEY + key + ALBUM_ART_FRAG + requestedId + COMMA + offset
+ connector.sendCommand(SRC_KEY + srcId + ALBUM_ART_FRAG + requestedId + COMMA + offset
+ COMMA + frag.length() + COMMA + frag);
} catch (NuvoException e) {
- logger.debug("Error sending ALBUMARTFRAG command for source: {}, artId: {}", key,
+ logger.debug("Error sending ALBUMARTFRAG command for source: {}, artId: {}", srcId,
requestedId);
}
}
}
}
break;
- case TYPE_FAVORITE_REQ:
+ case TYPE_NN_FAVORITE_REQ:
// ignore this update unless openHAB is handling this source
- if (nuvoNetSrcMap.get(key).equals(2)) {
- logger.debug("Favorite request for source: {} - favoriteId: {}", key, updateData);
+ if (nuvoNetSrcMap.get(srcId).equals(2)) {
+ logger.debug("Favorite request for source: {} - favoriteId: {}", srcId, updateData);
try {
int playlistIdx = Integer.parseInt(updateData, 16) - 1000;
- updateChannelState(NuvoEnum.valueOf(SOURCE + key), CHANNEL_BUTTON_PRESS,
- "PLAY_MUSIC_PRESET:" + favoriteMap.get(key)[playlistIdx]);
+ updateChannelState(NuvoEnum.valueOf(SOURCE + srcId), CHANNEL_BUTTON_PRESS,
+ "PLAY_MUSIC_PRESET:" + favoriteMap.get(srcId)[playlistIdx]);
} catch (NumberFormatException nfe) {
logger.debug("Unable to parse favoriteId: {}", updateData);
}
}
break;
default:
- logger.debug("onNewMessageEvent: unhandled key {}", key);
+ logger.debug("onNewMessageEvent: unhandled event type {}", type);
// Return here because receiving an unknown message does not indicate that one can poll
return;
}
diff --git a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties
index b882e74e5..4d69eef37 100644
--- a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties
+++ b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties
@@ -165,7 +165,7 @@ channel-type.nuvo.balance.description = Adjust the Balance Setting for the Zone
channel-type.nuvo.bass.label = Bass Adjustment
channel-type.nuvo.bass.description = Adjust the Bass Setting for the Zone
channel-type.nuvo.button_press.label = Button Pressed
-channel-type.nuvo.button_press.description = Indicates the Last Button Pressed On the Keypad for a Non NuvoNet Source
+channel-type.nuvo.button_press.description = Indicates the Last Button Pressed On the Keypad
channel-type.nuvo.control.label = Control
channel-type.nuvo.control.description = Transport Controls e.g. Play/Pause/Next/Previous for the Current Source
channel-type.nuvo.display_line1.label = Display Line 1
diff --git a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml
index 023af7f53..3b35889c4 100644
--- a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml
+++ b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml
@@ -342,6 +342,7 @@
+
@@ -518,7 +519,7 @@
String
- Indicates the Last Button Pressed On the Keypad for a Non NuvoNet Source
+ Indicates the Last Button Pressed On the Keypad