]> git.basschouten.com Git - openhab-addons.git/commitdiff
[rotel] Extension of amplifier A14's channel list (#12447)
authortonwi <wto.wit01@gmx.net>
Tue, 22 Mar 2022 19:48:18 +0000 (20:48 +0100)
committerGitHub <noreply@github.com>
Tue, 22 Mar 2022 19:48:18 +0000 (20:48 +0100)
* A14: new channels: tcbypass, balance, speakera and speakerb
* Specific balance set command for models A1x
* Channels added on other models
* In state TCBYPASS ON: 1) Ignore user adjustments on BASS/TREBLE. 2) Reset BASS/TREBLE to 0.

Signed-off-by: Wilhelm Tonsern <wto.wit01@gmx.net>
Also-by: Laurent Garnier <lg.hc@free.fr>
20 files changed:
bundles/org.openhab.binding.rotel/README.md
bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelBindingConstants.java
bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/RotelModel.java
bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelCommand.java
bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/communication/RotelConnector.java
bundles/org.openhab.binding.rotel/src/main/java/org/openhab/binding/rotel/internal/handler/RotelHandler.java
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/config/config.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel.properties
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a11.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a12.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/a14.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/channels.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra11.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra12.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1570.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1572.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/ra1592.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1570.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1572.xml
bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/thing/rc1590.xml

index 1204fc80497f70d34f8fc27aaa8e088d467bf8d1..ad3a2703e5c6533fe313b45192fd5fc988f6d9e0 100644 (file)
@@ -162,38 +162,42 @@ The following channels are available:
 | mainZone#line2 | Front Panel Line 2             | String    | The second line displayed on the device front panel      |                                    |
 | frequency      | Current Frequency              | Number    | The current frequency (in kHz) for digital source input  |                                    |
 | brightness     | Front Panel Display Brightness | Dimmer    | The backlight brightness level (in %) of the device front panel |                             |
+| tcbypass       | Tone Control Bypass            | Switch    | The user's bass-/treble-settings are bypassed            | ON, OFF                            |
+| balance        | Stereo Balance Adjustment      | Number    | Adjust the balance                                       | INCREASE, DECREASE, value          |
+| speakera       | Speaker-A Adjustment           | Switch    | Turn on/off the speaker group A                          | ON, OFF                            |
+| speakerb       | Speaker-B Adjustment           | Switch    | Turn on/off the speaker group B                          | ON, OFF                            |
 
 Here are the list of channels available for each thing type:
 
-| Thing Type | Available channels                                                                    |
-|------------|---------------------------------------------------------------------------------------|
-| a11        | power, source, volume, mute, bass, treble, brightness                                 |
-| a12        | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| a14        | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| cd11       | power, playControl, track, brightness                                                 |
-| cd14       | power, playControl, track, brightness                                                 |
-| ra11       | power, source, volume, mute, bass, treble, playControl, frequency, brightness         |
-| ra12       | power, source, volume, mute, bass, treble, playControl, frequency, brightness         |
-| ra1570     | power, source, volume, mute, bass, treble, playControl, frequency, brightness         |
-| ra1572     | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| ra1592     | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| rap1580    | power, source, dsp, volume, mute, brightness                                          |
-| rc1570     | power, source, volume, mute, bass, treble, playControl, frequency, brightness         |
-| rc1572     | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| rc1590     | power, source, volume, mute, bass, treble, frequency, brightness                      |
-| rcd1570    | power, playControl, brightness                                                        |
-| rcd1572    | power, playControl, track, brightness                                                 |
-| rcx1500    | power, source, volume, mute, playControl                                              |
-| rdd1580    | power, source, playControl, frequency                                                 |
-| rdg1520    | power, source, playControl                                                            |
+| Thing Type | Available channels                                                                                      |
+|------------|---------------------------------------------------------------------------------------------------------|
+| a11        | power, source, volume, mute, bass, treble, brightness, tcbypass, balance, speakera, speakerb            |
+| a12        | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
+| a14        | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
+| cd11       | power, playControl, track, brightness                                                                   |
+| cd14       | power, playControl, track, brightness                                                                   |
+| ra11       | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance        |
+| ra12       | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance        |
+| ra1570     | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance, speakera, speakerb |
+| ra1572     | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
+| ra1592     | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance, speakera, speakerb |
+| rap1580    | power, source, dsp, volume, mute, brightness                                                            |
+| rc1570     | power, source, volume, mute, bass, treble, playControl, frequency, brightness, tcbypass, balance        |
+| rc1572     | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance                     |
+| rc1590     | power, source, volume, mute, bass, treble, frequency, brightness, tcbypass, balance                     |
+| rcd1570    | power, playControl, brightness                                                                          |
+| rcd1572    | power, playControl, track, brightness                                                                   |
+| rcx1500    | power, source, volume, mute, playControl                                                                |
+| rdd1580    | power, source, playControl, frequency                                                                   |
+| rdg1520    | power, source, playControl                                                                              |
 | rsp1066    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volumeUpDown, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volumeUpDown |
 | rsp1068    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
 | rsp1069    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
 | rsp1098    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute |
 | rsp1570    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
 | rsp1572    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
-| rsp1576    | power, source, dsp, volume, mute, brightness                                          |
-| rsp1582    | power, source, dsp, volume, mute, brightness                                          |
+| rsp1576    | power, source, dsp, volume, mute, brightness                                                            |
+| rsp1582    | power, source, dsp, volume, mute, brightness                                                            |
 | rsx1055    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volumeUpDown, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volumeUpDown |
 | rsx1056    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute |
 | rsx1057    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute |
@@ -203,11 +207,11 @@ Here are the list of channels available for each thing type:
 | rsx1550    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
 | rsx1560    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#bass, mainZone#treble, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
 | rsx1562    | mainZone#power, mainZone#source, mainZone#recordSource, mainZone#dsp, mainZone#volume, mainZone#mute, mainZone#line1, mainZone#line2, zone2#power, zone2#source, zone2#volume, zone2#mute, zone3#power, zone3#source, zone3#volume, zone3#mute, zone4#power, zone4#source, zone4#volume, zone4#mute |
-| rt09       | power, source, playControl, brightness                                                |
-| rt11       | power, source, brightness                                                             |
-| rt1570     | power, source, brightness                                                             |
-| t11        | power, source, brightness                                                             |
-| t14        | power, source, brightness                                                             |
+| rt09       | power, source, playControl, brightness                                                                  |
+| rt11       | power, source, brightness                                                                               |
+| rt1570     | power, source, brightness                                                                               |
+| t11        | power, source, brightness                                                                               |
+| t14        | power, source, brightness                                                                               |
 
 ## Full Example
 
@@ -221,6 +225,8 @@ Thing rotel:rsp1570:preamp "RSP-1570" [ serialPort="COM2" ]
 Thing rotel:ra1592:preamp "RA-1592" [ serialPort="COM3" ]
 
 Thing rotel:cd14:cd "CD14" [ serialPort="COM4" ]
+
+Thing rotel:a14:amp "A14" [ serialPort="/dev/ttyUSB0" ]
 ```
 
 example.things using serial over IP connection:
@@ -282,6 +288,11 @@ Number amp_bass "Bass Adjustment [%d]" { channel="rotel:ra1592:preamp:bass" }
 Number amp_treble "Treble Adjustment [%d]" { channel="rotel:ra1592:preamp:treble" }
 Dimmer amp_brightness "Display brightness" { channel="rotel:ra1592:preamp:brightness" }
 
+Switch amp_bypass "TCBypass" { channel="rotel:a14:amp:tcbypass" }
+Number amp_balance "Balance Adjustment [%d]" { channel="rotel:a14:amp:balance" }
+Switch amp_speakera "Speaker A" { channel="rotel:a14:amp:speakera" }
+Switch amp_speakerb "Speaker B" { channel="rotel:a14:amp:speakerb" }
+
 Switch cd_power "Power" { channel="rotel:cd14:cd:power" }
 Player cd_control "Playback" { channel="rotel:cd14:cd:power" }
 Number cd_track "Track [%d]" { channel="rotel:cd14:cd:power" }
index 559c6c4051d6fa681d23d7235758c81db2afff8a..651296b705e907abbdae8892b03521ae6f7abc44 100644 (file)
@@ -148,6 +148,10 @@ public class RotelBindingConstants {
     public static final String CHANNEL_ZONE4_SOURCE = "zone4#source";
     public static final String CHANNEL_ZONE4_VOLUME = "zone4#volume";
     public static final String CHANNEL_ZONE4_MUTE = "zone4#mute";
+    public static final String CHANNEL_TCBYPASS = "tcbypass";
+    public static final String CHANNEL_BALANCE = "balance";
+    public static final String CHANNEL_SPEAKER_A = "speakera";
+    public static final String CHANNEL_SPEAKER_B = "speakerb";
 
     // List of all properties
     public static final String PROPERTY_PROTOCOL = "protocol";
index 31039c3de91ad562f08e2059c87ad1b151413db5..ec7c236c12ac0a42f83d1aa9ab01d00ccbc03b0e 100644 (file)
@@ -62,21 +62,27 @@ public enum RotelModel {
             5, true, RotelFlagsMapping.MAPPING5),
     RSX1562("RSX-1562", 115200, 2, 3, true, 96, true, null, false, RotelCommand.RECORD_FONCTION_SELECT, 4, (byte) 0xCC,
             42, 5, true, RotelFlagsMapping.MAPPING5),
-    A11("A11", 115200, 4, 96, true, 10, false, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
-    A12("A12", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
-    A14("A14", 115200, 5, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
+    A11("A11", 115200, 4, 96, true, 10, 15, false, -1, false, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
+    A12("A12", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
+    A14("A14", 115200, 5, 96, true, 10, 15, false, -1, true, true, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
     CD11("CD11", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
     CD14("CD14", 57600, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.NO_SPECIAL_CHARACTERS),
-    RA11("RA-11", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RA12("RA-12", 115200, 6, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RA1570("RA-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RA1572("RA-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RA1592("RA-1592", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
+    RA11("RA-11", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
+    RA12("RA-12", 115200, 6, 96, true, 10, 15, true, -1, true, false, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
+    RA1570("RA-1570", 115200, 7, 96, true, 10, 15, true, -1, true, true, false, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
+    RA1572("RA-1572", 115200, 8, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
+    RA1592("RA-1592", 115200, 9, 96, true, 10, 15, false, -1, true, true, true, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
     RAP1580("RAP-1580", 115200, 11, 96, true, null, false, 5, false, false, -10, 10,
             RotelConnector.NO_SPECIAL_CHARACTERS),
-    RC1570("RC-1570", 115200, 7, 96, true, 10, true, -1, true, false, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RC1572("RC-1572", 115200, 8, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
-    RC1590("RC-1590", 115200, 9, 96, true, 10, false, -1, true, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
+    RC1570("RC-1570", 115200, 7, 96, true, 10, 15, true, -1, true, false, false, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
+    RC1572("RC-1572", 115200, 8, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
+    RC1590("RC-1590", 115200, 9, 96, true, 10, 15, false, -1, true, false, true, 6, 0,
+            RotelConnector.SPECIAL_CHARACTERS),
     RCD1570("RCD-1570", 115200, 0, null, false, null, true, -1, false, true, 6, 0, RotelConnector.SPECIAL_CHARACTERS),
     RCD1572("RCD-1572", 57600, 0, null, false, null, true, -1, false, true, 6, 0,
             RotelConnector.SPECIAL_CHARACTERS_RCD1572),
@@ -118,6 +124,8 @@ public enum RotelModel {
     private boolean charsBeforeFlags;
     private RotelFlagsMapping flagsMapping;
     private byte[][] specialCharacters;
+    private @Nullable Integer balanceLevelMax;
+    private boolean getSpeakerGroupsAvailable;
 
     /**
      * Constructor
@@ -144,8 +152,8 @@ public enum RotelModel {
             @Nullable RotelCommand zoneSelectCmd, int dspCategory, byte deviceId, int respNbChars, int respNbFlags,
             boolean charsBeforeFlags, RotelFlagsMapping flagsMapping) {
         this(name, baudRate, RotelCommand.DISPLAY_REFRESH, sourceCategory, nbAdditionalZones, additionalCommands,
-                volumeMax, directVolume, toneLevelMax, playControl, zoneSelectCmd, dspCategory, false, false, null,
-                null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping,
+                volumeMax, directVolume, toneLevelMax, null, playControl, zoneSelectCmd, dspCategory, false, false,
+                false, null, null, deviceId, respNbChars, respNbFlags, charsBeforeFlags, flagsMapping,
                 RotelConnector.NO_SPECIAL_CHARACTERS);
     }
 
@@ -170,11 +178,40 @@ public enum RotelModel {
             @Nullable Integer toneLevelMax, boolean playControl, int dspCategory, boolean getFrequencyAvailable,
             boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax,
             byte[][] specialCharacters) {
-        this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax,
-                playControl, null, dspCategory, getFrequencyAvailable, getDimmerLevelAvailable, diummerLevelMin,
+        this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax, null,
+                playControl, null, dspCategory, getFrequencyAvailable, false, getDimmerLevelAvailable, diummerLevelMin,
                 diummerLevelMax, (byte) 0, 0, 0, false, RotelFlagsMapping.NO_MAPPING, specialCharacters);
     }
 
+    /**
+     * Constructor
+     *
+     * @param name the model name
+     * @param baudRate the baud rate to be used for the RS232 communication
+     * @param sourceCategory the category from {@link RotelSource}
+     * @param volumeMax the maximum volume or null if no volume management is available
+     * @param directVolume true if a command to set the volume with a value is available
+     * @param toneLevelMax the maximum tone level or null if no bass/treble management is available
+     * @param balanceLevelMax the maximum balance level or null if no balance management is available
+     * @param playControl true if control of source playback is available
+     * @param dspCategory the category from {@link RotelDsp}
+     * @param getFrequencyAvailable true if the command to get the frequency for digital source input is available
+     * @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available
+     * @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available
+     * @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable
+     * @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable
+     * @param specialCharacters the table of special characters that can be found in the standard response message
+     */
+    private RotelModel(String name, int baudRate, int sourceCategory, @Nullable Integer volumeMax, boolean directVolume,
+            @Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl, int dspCategory,
+            boolean getFrequencyAvailable, boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable,
+            @Nullable Integer diummerLevelMin, @Nullable Integer diummerLevelMax, byte[][] specialCharacters) {
+        this(name, baudRate, RotelCommand.POWER, sourceCategory, 0, false, volumeMax, directVolume, toneLevelMax,
+                balanceLevelMax, playControl, null, dspCategory, getFrequencyAvailable, getSpeakerGroupsAvailable,
+                getDimmerLevelAvailable, diummerLevelMin, diummerLevelMax, (byte) 0, 0, 0, false,
+                RotelFlagsMapping.NO_MAPPING, specialCharacters);
+    }
+
     /**
      * Constructor
      *
@@ -187,10 +224,12 @@ public enum RotelModel {
      * @param volumeMax the maximum volume or null if no volume management is available
      * @param directVolume true if a command to set the volume with a value is available
      * @param toneLevelMax the maximum tone level or null if no bass/treble management is available
+     * @param balanceLevelMax the maximum balance level or null if no balance management is available
      * @param playControl true if control of source playback is available
      * @param zoneSelectCmd the command to be used to select a zone
      * @param dspCategory the category from {@link RotelDsp}
      * @param getFrequencyAvailable true if the command to get the frequency for digital source input is available
+     * @param getSpeakerGroupsAvailable true if the command to switch speaker groups is available
      * @param getDimmerLevelAvailable true if the command to get the front display dimmer level is available
      * @param diummerLevelMin the minimum front display dimmer level or null if dimmer control is unavailable
      * @param diummerLevelMax the maximum front display dimmer level or null if dimmer control is unavailable
@@ -203,8 +242,9 @@ public enum RotelModel {
      */
     private RotelModel(String name, int baudRate, RotelCommand powerStateCmd, int sourceCategory, int nbAdditionalZones,
             boolean additionalCommands, @Nullable Integer volumeMax, boolean directVolume,
-            @Nullable Integer toneLevelMax, boolean playControl, @Nullable RotelCommand zoneSelectCmd, int dspCategory,
-            boolean getFrequencyAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin,
+            @Nullable Integer toneLevelMax, @Nullable Integer balanceLevelMax, boolean playControl,
+            @Nullable RotelCommand zoneSelectCmd, int dspCategory, boolean getFrequencyAvailable,
+            boolean getSpeakerGroupsAvailable, boolean getDimmerLevelAvailable, @Nullable Integer diummerLevelMin,
             @Nullable Integer diummerLevelMax, byte deviceId, int respNbChars, int respNbFlags,
             boolean charsBeforeFlags, RotelFlagsMapping flagsMapping, byte[][] specialCharacters) {
         this.name = name;
@@ -216,10 +256,12 @@ public enum RotelModel {
         this.volumeMax = volumeMax;
         this.directVolume = directVolume;
         this.toneLevelMax = toneLevelMax;
+        this.balanceLevelMax = balanceLevelMax;
         this.playControl = playControl;
         this.zoneSelectCmd = zoneSelectCmd;
         this.dspCategory = dspCategory;
         this.getFrequencyAvailable = getFrequencyAvailable;
+        this.getSpeakerGroupsAvailable = getSpeakerGroupsAvailable;
         this.getDimmerLevelAvailable = getDimmerLevelAvailable;
         this.diummerLevelMin = diummerLevelMin;
         this.diummerLevelMax = diummerLevelMax;
@@ -386,6 +428,34 @@ public enum RotelModel {
         return toneLevelMax != null ? toneLevelMax.intValue() : 0;
     }
 
+    /**
+     * Inform whether balance control is available
+     *
+     * @return true if balance control is available
+     */
+    public boolean hasBalanceControl() {
+        return balanceLevelMax != null;
+    }
+
+    /**
+     * Get the maximum balance level
+     *
+     * @return the maximum balance level or 0
+     */
+    public int getBalanceLevelMax() {
+        Integer balanceLevelMax = this.balanceLevelMax;
+        return balanceLevelMax != null ? balanceLevelMax.intValue() : 0;
+    }
+
+    /**
+     * Inform whether the command to switch speaker groups is available
+     *
+     * @return true if the command is available
+     */
+    public boolean hasSpeakerGroups() {
+        return getSpeakerGroupsAvailable;
+    }
+
     /**
      * Inform whether the command to get the current frequency for digital source input is available
      *
index 0924f9f870447e26ec3dcaaba024dcb77259b467..bfbefd1abd22b4bb20ee6080f9e32396e0ec32e2 100644 (file)
@@ -227,12 +227,30 @@ public enum RotelCommand {
     TRACK_FORWARD("Track Forward", RotelConnector.PRIMARY_CMD, (byte) 0x09, "track_fwd", "trkf"),
     TRACK_BACKWORD("Track Backward", RotelConnector.PRIMARY_CMD, (byte) 0x08, "track_back", "trkb"),
     TRACK("Request current CD track number", null, "track"),
-    FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq"),
+    FREQUENCY("Request current frequency for digital source input", "get_current_freq", "freq?"),
     DISPLAY_REFRESH("Display Refresh", RotelConnector.PRIMARY_CMD, (byte) 0xFF),
-    DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer"),
+    DIMMER_LEVEL_GET("Request current front display dimmer level", "get_current_dimmer", "dimmer?"),
     DIMMER_LEVEL_SET("Set front display dimmer to level", "dimmer_", "dimmer_"),
     UPDATE_AUTO("Set Update to Auto", "display_update_auto", "rs232_update_on"),
-    UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off");
+    UPDATE_MANUAL("Set Update to Manual", "display_update_manual", "rs232_update_off"),
+    TONE_CONTROLS_ON("Tone Controls On", "tone_on", null),
+    TONE_CONTROLS_OFF("Tone Controls Off", "tone_off", null),
+    TONE_CONTROLS("Request current tone control state", "get_tone", null),
+    TCBYPASS_ON("Bypass On", null, "bypass_on"),
+    TCBYPASS_OFF("Bypass Off", null, "bypass_off"),
+    TCBYPASS("Request current tone bypass state", null, "bypass?"),
+    BALANCE_RIGHT("Balance Right", "balance_right", "balance_r"),
+    BALANCE_LEFT("Balance Left", "balance_left", "balance_l"),
+    BALANCE_SET("Set Balance to level", "balance_", "balance_"),
+    BALANCE_SET_FIX("Set Balance to level", "balance_", "balance_"),
+    BALANCE("Request current balance setting", "get_balance", "balance?"),
+    SPEAKER_A_TOGGLE("Toggle Speaker A Output", RotelConnector.PRIMARY_CMD, (byte) 0x50, "speaker_a", "speaker_a"),
+    SPEAKER_A_ON("Set Speaker A Output", "speaker_a_on", "speaker_a_on"),
+    SPEAKER_A_OFF("Unset Speaker A Output", "speaker_a_off", "speaker_a_off"),
+    SPEAKER_B_TOGGLE("Toggle Speaker B Output", RotelConnector.PRIMARY_CMD, (byte) 0x51, "speaker_b", "speaker_b"),
+    SPEAKER_B_ON("Set Speaker B Output", "speaker_b_on", "speaker_b_on"),
+    SPEAKER_B_OFF("Unset Speaker B Output", "speaker_b_off", "speaker_b_off"),
+    SPEAKER("Request current active speaker outputs", "get_current_speaker", "speaker?");
 
     public static final byte PRIMARY_COMMAND = (byte) 0x10;
 
index de749ff6fa34618a1f31a22a31b7ecbd7aa15511..fec2effc2719c0cb8bfaae67b8d3cf4aac5222be 100644 (file)
@@ -136,6 +136,10 @@ public abstract class RotelConnector {
     public static final String KEY_DSP_MODE = "dsp_mode";
     public static final String KEY_DIMMER = "dimmer";
     public static final String KEY_FREQ = "freq";
+    public static final String KEY_TONE = "tone";
+    public static final String KEY_TCBYPASS = "bypass";
+    public static final String KEY_BALANCE = "balance";
+    public static final String KEY_SPEAKER = "speaker";
 
     // Special keys used by the binding
     public static final String KEY_LINE1 = "line1";
@@ -171,6 +175,9 @@ public abstract class RotelConnector {
     public static final String PAUSE = "pause";
     public static final String STOP = "stop";
     private static final String SOURCE = "source";
+    public static final String MSG_VALUE_SPEAKER_A = "a";
+    public static final String MSG_VALUE_SPEAKER_B = "b";
+    public static final String MSG_VALUE_SPEAKER_AB = "a_b";
 
     private RotelModel model;
     private RotelProtocol protocol;
@@ -458,6 +465,27 @@ public abstract class RotelConnector {
                                     messageStr += String.format("-%02d", -value);
                                 }
                                 break;
+                            case BALANCE_SET:
+                                if (value == 0) {
+                                    messageStr += "000";
+                                } else if (value > 0) {
+                                    messageStr += String.format("R%02d", value);
+                                } else {
+                                    messageStr += String.format("L%02d", -value);
+                                }
+                                break;
+                            case BALANCE_SET_FIX:
+                                // Firmware for models A1x does not follow strictly the Rotel specification
+                                // The firmware expects values like r05 or l04 while the specification mentions
+                                // R05 and L04
+                                if (value == 0) {
+                                    messageStr += "000";
+                                } else if (value > 0) {
+                                    messageStr += String.format("r%02d", value);
+                                } else {
+                                    messageStr += String.format("l%02d", -value);
+                                }
+                                break;
                             case DIMMER_LEVEL_SET:
                                 if (value > 0 && model.getDimmerLevelMin() < 0) {
                                     messageStr += String.format("+%d", value);
index f07db499ed7ecf348f3a96089cc775d0dc7435f1..01c8ed0554e3ce064bf8e0c249ad5f733318cdf3 100644 (file)
@@ -75,6 +75,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
     private static final RotelModel DEFAULT_MODEL = RotelModel.RSP1066;
     private static final long POLLING_INTERVAL = TimeUnit.SECONDS.toSeconds(60);
     private static final boolean USE_SIMULATED_DEVICE = false;
+    private static final int SLEEP_INTV = 30;
 
     private @Nullable ScheduledFuture<?> reconnectJob;
     private @Nullable ScheduledFuture<?> powerOnJob;
@@ -125,6 +126,13 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
     private String frontPanelLine1 = "";
     private String frontPanelLine2 = "";
     private int brightness;
+    private boolean tcbypass;
+    private int balance;
+    private int minBalanceLevel;
+    private int maxBalanceLevel;
+    private boolean speakera;
+    private boolean speakerb;
+    private boolean useFixedBalanceCmd;
 
     private Object sequenceLock = new Object();
 
@@ -191,12 +199,15 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                 break;
             case THING_TYPE_ID_A11:
                 rotelModel = RotelModel.A11;
+                useFixedBalanceCmd = true;
                 break;
             case THING_TYPE_ID_A12:
                 rotelModel = RotelModel.A12;
+                useFixedBalanceCmd = true;
                 break;
             case THING_TYPE_ID_A14:
                 rotelModel = RotelModel.A14;
+                useFixedBalanceCmd = true;
                 break;
             case THING_TYPE_ID_CD11:
                 rotelModel = RotelModel.CD11;
@@ -312,6 +323,12 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                     "Set minValue to {} and maxValue to {} for your sitemap widget attached to your bass or treble item.",
                     minToneLevel, maxToneLevel);
         }
+        if (rotelModel.hasBalanceControl()) {
+            maxBalanceLevel = rotelModel.getBalanceLevelMax();
+            minBalanceLevel = -maxBalanceLevel;
+            logger.info("Set minValue to {} and maxValue to {} for your sitemap widget attached to your balance item.",
+                    minBalanceLevel, maxBalanceLevel);
+        }
 
         // Check configuration settings
         String configError = null;
@@ -519,6 +536,18 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                                     : src.getCommand();
                             if (cmd != null) {
                                 connector.sendCommand(cmd);
+                                if (connector.getModel().canGetFrequency()) {
+                                    // send <new-source> returns
+                                    // 1.) the selected <new-source>
+                                    // 2.) the used frequency
+                                    // BUT:
+                                    // at response-time the frequency has the value of <old-source>
+                                    // so we must wait a short moment to get the frequency of <new-source>
+                                    Thread.sleep(1000);
+                                    connector.sendCommand(RotelCommand.FREQUENCY);
+                                    Thread.sleep(100);
+                                    updateChannelState(CHANNEL_FREQUENCY);
+                                }
                             } else {
                                 success = false;
                                 logger.debug("Command {} from channel {} failed: undefined source command", command,
@@ -788,6 +817,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                         if (!isPowerOn()) {
                             success = false;
                             logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else if (tcbypass) {
+                            logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
+                                    channel);
+                            updateChannelState(CHANNEL_BASS);
                         } else {
                             handleToneCmd(bass, channel, command, 2, RotelCommand.BASS_UP, RotelCommand.BASS_DOWN,
                                     RotelCommand.BASS_SET);
@@ -798,6 +831,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                         if (!isPowerOn()) {
                             success = false;
                             logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else if (tcbypass) {
+                            logger.debug("Command {} from channel {} ignored: tone control bypass is ON", command,
+                                    channel);
+                            updateChannelState(CHANNEL_TREBLE);
                         } else {
                             handleToneCmd(treble, channel, command, 1, RotelCommand.TREBLE_UP, RotelCommand.TREBLE_DOWN,
                                     RotelCommand.TREBLE_SET);
@@ -815,7 +852,7 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                                     && connector.getModel() != RotelModel.RCD1570
                                     && connector.getModel() != RotelModel.RCD1572
                                     && connector.getModel() != RotelModel.RCX1500) {
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                                 connector.sendCommand(RotelCommand.PLAY_STATUS);
                             }
                         } else if (command instanceof NextPreviousType && command == NextPreviousType.NEXT) {
@@ -845,6 +882,55 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                             logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
                         }
                         break;
+                    case CHANNEL_TCBYPASS:
+                        if (!isPowerOn()) {
+                            success = false;
+                            logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else if (!connector.getModel().hasToneControl()
+                                || connector.getProtocol() == RotelProtocol.HEX) {
+                            success = false;
+                            logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
+                        } else {
+                            handleTcbypassCmd(channel, command,
+                                    connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_OFF
+                                            : RotelCommand.TCBYPASS_ON,
+                                    connector.getProtocol() == RotelProtocol.ASCII_V1 ? RotelCommand.TONE_CONTROLS_ON
+                                            : RotelCommand.TCBYPASS_OFF);
+                        }
+                        break;
+                    case CHANNEL_BALANCE:
+                        if (!isPowerOn()) {
+                            success = false;
+                            logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else if (!connector.getModel().hasBalanceControl()
+                                || connector.getProtocol() == RotelProtocol.HEX) {
+                            success = false;
+                            logger.debug("Command {} from channel {} failed: unavailable feature", command, channel);
+                        } else {
+                            handleBalanceCmd(channel, command, RotelCommand.BALANCE_LEFT, RotelCommand.BALANCE_RIGHT,
+                                    useFixedBalanceCmd ? RotelCommand.BALANCE_SET_FIX : RotelCommand.BALANCE_SET);
+                        }
+                        break;
+                    case CHANNEL_SPEAKER_A:
+                        if (!isPowerOn()) {
+                            success = false;
+                            logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else {
+                            handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command,
+                                    RotelCommand.SPEAKER_A_ON, RotelCommand.SPEAKER_A_OFF,
+                                    RotelCommand.SPEAKER_A_TOGGLE);
+                        }
+                        break;
+                    case CHANNEL_SPEAKER_B:
+                        if (!isPowerOn()) {
+                            success = false;
+                            logger.debug("Command {} from channel {} ignored: device in standby", command, channel);
+                        } else {
+                            handleSpeakerCmd(connector.getProtocol() == RotelProtocol.HEX, channel, command,
+                                    RotelCommand.SPEAKER_B_ON, RotelCommand.SPEAKER_B_OFF,
+                                    RotelCommand.SPEAKER_B_TOGGLE);
+                        }
+                        break;
                     default:
                         success = false;
                         logger.debug("Command {} from channel {} failed: nnexpected command", command, channel);
@@ -992,6 +1078,92 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
         }
     }
 
+    /**
+     * Handle a tcbypass command (only for ASCII protocol)
+     *
+     * @param channel the channel
+     * @param command the received channel command (OnOffType)
+     * @param onCmd the command to be sent to the device to bypass_on
+     * @param offCmd the command to be sent to the device to bypass_off
+     *
+     * @throws RotelException in case of communication error with the device
+     */
+    private void handleTcbypassCmd(String channel, Command command, RotelCommand onCmd, RotelCommand offCmd)
+            throws RotelException, InterruptedException {
+        if (command instanceof OnOffType) {
+            if (command == OnOffType.ON) {
+                connector.sendCommand(onCmd);
+                bass = 0;
+                treble = 0;
+                updateChannelState(CHANNEL_BASS);
+                updateChannelState(CHANNEL_TREBLE);
+            } else if (command == OnOffType.OFF) {
+                connector.sendCommand(offCmd);
+                Thread.sleep(200);
+                connector.sendCommand(RotelCommand.BASS);
+                Thread.sleep(200);
+                connector.sendCommand(RotelCommand.TREBLE);
+            }
+        } else {
+            logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
+        }
+    }
+
+    /**
+     * Handle a speaker command
+     *
+     * @param onlyToggle true if only the toggle command must be used
+     * @param channel the channel
+     * @param command the received channel command (OnOffType)
+     * @param onCmd the command to be sent to the device to speaker_x_on
+     * @param offCmd the command to be sent to the device to speaker_x_off
+     * @param toggleCmd the command to be sent to the device to toggle the speaker_x state
+     *
+     * @throws RotelException in case of communication error with the device
+     */
+    private void handleSpeakerCmd(boolean onlyToggle, String channel, Command command, RotelCommand onCmd,
+            RotelCommand offCmd, RotelCommand toggleCmd) throws RotelException {
+        if (command instanceof OnOffType) {
+            if (onlyToggle) {
+                connector.sendCommand(toggleCmd);
+            } else if (command == OnOffType.ON) {
+                connector.sendCommand(onCmd);
+            } else if (command == OnOffType.OFF) {
+                connector.sendCommand(offCmd);
+            }
+        } else {
+            logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
+        }
+    }
+
+    /**
+     * Handle a tone balance adjustment command (left or right) (only for ASCII protocol)
+     *
+     * @param channel the channel
+     * @param command the received channel command (IncreaseDecreaseType or DecimalType)
+     * @param rightCmd the command to be sent to the device to "increase" balance (shift to the right side)
+     * @param leftCmd the command to be sent to the device to "decrease" balance (shift to the left side)
+     * @param setCmd the command to be sent to the device to set the balance at a value
+     *
+     * @throws RotelException in case of communication error with the device
+     * @throws InterruptedException in case of interruption during a thread sleep
+     */
+    private void handleBalanceCmd(String channel, Command command, RotelCommand leftCmd, RotelCommand rightCmd,
+            RotelCommand setCmd) throws RotelException, InterruptedException {
+        if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.INCREASE) {
+            connector.sendCommand(rightCmd);
+        } else if (command instanceof IncreaseDecreaseType && command == IncreaseDecreaseType.DECREASE) {
+            connector.sendCommand(leftCmd);
+        } else if (command instanceof DecimalType) {
+            int value = ((DecimalType) command).intValue();
+            if (value >= minBalanceLevel && value <= maxBalanceLevel) {
+                connector.sendCommand(setCmd, value);
+            }
+        } else {
+            logger.debug("Command {} from channel {} failed: invalid command value", command, channel);
+        }
+    }
+
     /**
      * Run a sequence of commands to display the current tone level (bass or treble) on the device front panel
      *
@@ -1377,6 +1549,67 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                 case RotelConnector.KEY_UPDATE_MODE:
                 case RotelConnector.KEY_DISPLAY_UPDATE:
                     break;
+                case RotelConnector.KEY_TONE:
+                    if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) {
+                        tcbypass = false;
+                        updateChannelState(CHANNEL_TCBYPASS);
+                    } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
+                        tcbypass = true;
+                        updateChannelState(CHANNEL_TCBYPASS);
+                    } else {
+                        throw new RotelException("Invalid value");
+                    }
+                    break;
+                case RotelConnector.KEY_TCBYPASS:
+                    if (RotelConnector.MSG_VALUE_ON.equalsIgnoreCase(value)) {
+                        tcbypass = true;
+                        updateChannelState(CHANNEL_TCBYPASS);
+                    } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
+                        tcbypass = false;
+                        updateChannelState(CHANNEL_TCBYPASS);
+                    } else {
+                        throw new RotelException("Invalid value");
+                    }
+                    break;
+                case RotelConnector.KEY_BALANCE:
+                    if (RotelConnector.MSG_VALUE_MIN.equalsIgnoreCase(value)) {
+                        balance = minBalanceLevel;
+                    } else if (RotelConnector.MSG_VALUE_MAX.equalsIgnoreCase(value)) {
+                        balance = maxBalanceLevel;
+                    } else if (value.toUpperCase().startsWith("L")) {
+                        balance = -Integer.parseInt(value.substring(1));
+                    } else if (value.toLowerCase().startsWith("R")) {
+                        balance = Integer.parseInt(value.substring(1));
+                    } else {
+                        balance = Integer.parseInt(value);
+                    }
+                    updateChannelState(CHANNEL_BALANCE);
+                    break;
+                case RotelConnector.KEY_SPEAKER:
+                    if (RotelConnector.MSG_VALUE_SPEAKER_A.equalsIgnoreCase(value)) {
+                        speakera = true;
+                        speakerb = false;
+                        updateChannelState(CHANNEL_SPEAKER_A);
+                        updateChannelState(CHANNEL_SPEAKER_B);
+                    } else if (RotelConnector.MSG_VALUE_SPEAKER_B.equalsIgnoreCase(value)) {
+                        speakera = false;
+                        speakerb = true;
+                        updateChannelState(CHANNEL_SPEAKER_A);
+                        updateChannelState(CHANNEL_SPEAKER_B);
+                    } else if (RotelConnector.MSG_VALUE_SPEAKER_AB.equalsIgnoreCase(value)) {
+                        speakera = true;
+                        speakerb = true;
+                        updateChannelState(CHANNEL_SPEAKER_A);
+                        updateChannelState(CHANNEL_SPEAKER_B);
+                    } else if (RotelConnector.MSG_VALUE_OFF.equalsIgnoreCase(value)) {
+                        speakera = false;
+                        speakerb = false;
+                        updateChannelState(CHANNEL_SPEAKER_A);
+                        updateChannelState(CHANNEL_SPEAKER_B);
+                    } else {
+                        throw new RotelException("Invalid value");
+                    }
+                    break;
                 default:
                     logger.debug("onNewMessageEvent: unhandled key {}", key);
                     break;
@@ -1425,6 +1658,10 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
         updateChannelState(CHANNEL_TRACK);
         updateChannelState(CHANNEL_FREQUENCY);
         updateChannelState(CHANNEL_BRIGHTNESS);
+        updateChannelState(CHANNEL_TCBYPASS);
+        updateChannelState(CHANNEL_BALANCE);
+        updateChannelState(CHANNEL_SPEAKER_A);
+        updateChannelState(CHANNEL_SPEAKER_B);
     }
 
     /**
@@ -1582,11 +1819,11 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                                     && connector.getModel() != RotelModel.RSP1576
                                     && connector.getModel() != RotelModel.RSP1582) {
                                 connector.sendCommand(RotelCommand.UPDATE_AUTO);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasSourceControl()) {
                                 connector.sendCommand(RotelCommand.SOURCE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasVolumeControl() || connector.getModel().hasToneControl()) {
                                 if (connector.getModel().hasVolumeControl()
@@ -1594,96 +1831,116 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                                         && connector.getModel() != RotelModel.RSP1576
                                         && connector.getModel() != RotelModel.RSP1582) {
                                     connector.sendCommand(RotelCommand.VOLUME_GET_MIN);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                     connector.sendCommand(RotelCommand.VOLUME_GET_MAX);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                 }
                                 if (connector.getModel().hasToneControl()) {
                                     connector.sendCommand(RotelCommand.TONE_MAX);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                 }
                                 // Wait enough to be sure to get the min/max values requested just before
                                 Thread.sleep(250);
                                 if (connector.getModel().hasVolumeControl()) {
                                     connector.sendCommand(RotelCommand.VOLUME_GET);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                     if (connector.getModel() != RotelModel.RA11
                                             && connector.getModel() != RotelModel.RA12
                                             && connector.getModel() != RotelModel.RCX1500) {
                                         connector.sendCommand(RotelCommand.MUTE);
-                                        Thread.sleep(50);
+                                        Thread.sleep(SLEEP_INTV);
                                     }
                                 }
                                 if (connector.getModel().hasToneControl()) {
                                     connector.sendCommand(RotelCommand.BASS);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                     connector.sendCommand(RotelCommand.TREBLE);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
+                                    connector.sendCommand(RotelCommand.TONE_CONTROLS);
+                                    Thread.sleep(SLEEP_INTV);
                                 }
                             }
+                            if (connector.getModel().hasBalanceControl()) {
+                                connector.sendCommand(RotelCommand.BALANCE);
+                                Thread.sleep(SLEEP_INTV);
+                            }
                             if (connector.getModel().hasPlayControl()) {
                                 if (connector.getModel() != RotelModel.RCD1570
                                         && connector.getModel() != RotelModel.RCD1572
                                         && (connector.getModel() != RotelModel.RCX1500
                                                 || !source.getName().equals("CD"))) {
                                     connector.sendCommand(RotelCommand.PLAY_STATUS);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                 } else {
                                     connector.sendCommand(RotelCommand.CD_PLAY_STATUS);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                 }
                             }
                             if (connector.getModel().hasDspControl()) {
                                 connector.sendCommand(RotelCommand.DSP_MODE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().canGetFrequency()) {
                                 connector.sendCommand(RotelCommand.FREQUENCY);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) {
                                 connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
+                            }
+                            if (connector.getModel().hasSpeakerGroups()) {
+                                connector.sendCommand(RotelCommand.SPEAKER);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             break;
                         case ASCII_V2:
                             connector.sendCommand(RotelCommand.UPDATE_AUTO);
-                            Thread.sleep(50);
+                            Thread.sleep(SLEEP_INTV);
                             if (connector.getModel().hasSourceControl()) {
                                 connector.sendCommand(RotelCommand.SOURCE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasVolumeControl()) {
                                 connector.sendCommand(RotelCommand.VOLUME_GET);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                                 connector.sendCommand(RotelCommand.MUTE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasToneControl()) {
                                 connector.sendCommand(RotelCommand.BASS);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                                 connector.sendCommand(RotelCommand.TREBLE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
+                                connector.sendCommand(RotelCommand.TCBYPASS);
+                                Thread.sleep(SLEEP_INTV);
+                            }
+                            if (connector.getModel().hasBalanceControl()) {
+                                connector.sendCommand(RotelCommand.BALANCE);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasPlayControl()) {
                                 connector.sendCommand(RotelCommand.PLAY_STATUS);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                                 if (source.getName().equals("CD") && !connector.getModel().hasSourceControl()) {
                                     connector.sendCommand(RotelCommand.TRACK);
-                                    Thread.sleep(50);
+                                    Thread.sleep(SLEEP_INTV);
                                 }
                             }
                             if (connector.getModel().hasDspControl()) {
                                 connector.sendCommand(RotelCommand.DSP_MODE);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().canGetFrequency()) {
                                 connector.sendCommand(RotelCommand.FREQUENCY);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             if (connector.getModel().hasDimmerControl() && connector.getModel().canGetDimmerLevel()) {
                                 connector.sendCommand(RotelCommand.DIMMER_LEVEL_GET);
-                                Thread.sleep(50);
+                                Thread.sleep(SLEEP_INTV);
+                            }
+                            if (connector.getModel().hasSpeakerGroups()) {
+                                connector.sendCommand(RotelCommand.SPEAKER);
+                                Thread.sleep(SLEEP_INTV);
                             }
                             break;
                     }
@@ -1907,18 +2164,19 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
         switch (channel) {
             case CHANNEL_POWER:
             case CHANNEL_MAIN_POWER:
-                if (power != null) {
-                    state = power ? OnOffType.ON : OnOffType.OFF;
+                Boolean po = power;
+                if (po != null) {
+                    state = OnOffType.from(po.booleanValue());
                 }
                 break;
             case CHANNEL_ZONE2_POWER:
-                state = powerZone2 ? OnOffType.ON : OnOffType.OFF;
+                state = OnOffType.from(powerZone2);
                 break;
             case CHANNEL_ZONE3_POWER:
-                state = powerZone3 ? OnOffType.ON : OnOffType.OFF;
+                state = OnOffType.from(powerZone3);
                 break;
             case CHANNEL_ZONE4_POWER:
-                state = powerZone4 ? OnOffType.ON : OnOffType.OFF;
+                state = OnOffType.from(powerZone4);
                 break;
             case CHANNEL_SOURCE:
             case CHANNEL_MAIN_SOURCE:
@@ -1998,22 +2256,22 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
             case CHANNEL_MUTE:
             case CHANNEL_MAIN_MUTE:
                 if (isPowerOn()) {
-                    state = mute ? OnOffType.ON : OnOffType.OFF;
+                    state = OnOffType.from(mute);
                 }
                 break;
             case CHANNEL_ZONE2_MUTE:
                 if (powerZone2) {
-                    state = muteZone2 ? OnOffType.ON : OnOffType.OFF;
+                    state = OnOffType.from(muteZone2);
                 }
                 break;
             case CHANNEL_ZONE3_MUTE:
                 if (powerZone3) {
-                    state = muteZone3 ? OnOffType.ON : OnOffType.OFF;
+                    state = OnOffType.from(muteZone3);
                 }
                 break;
             case CHANNEL_ZONE4_MUTE:
                 if (powerZone4) {
-                    state = muteZone4 ? OnOffType.ON : OnOffType.OFF;
+                    state = OnOffType.from(muteZone4);
                 }
                 break;
             case CHANNEL_BASS:
@@ -2066,6 +2324,26 @@ public class RotelHandler extends BaseThingHandler implements RotelMessageEventL
                     state = new PercentType(BigDecimal.valueOf(dimmerPct));
                 }
                 break;
+            case CHANNEL_TCBYPASS:
+                if (isPowerOn()) {
+                    state = OnOffType.from(tcbypass);
+                }
+                break;
+            case CHANNEL_BALANCE:
+                if (isPowerOn()) {
+                    state = new DecimalType(balance);
+                }
+                break;
+            case CHANNEL_SPEAKER_A:
+                if (isPowerOn()) {
+                    state = OnOffType.from(speakera);
+                }
+                break;
+            case CHANNEL_SPEAKER_B:
+                if (isPowerOn()) {
+                    state = OnOffType.from(speakerb);
+                }
+                break;
             default:
                 break;
         }
index 382320b399175a82c357bba3897eab69e7412820..197817913f2b9e66af10f1cf91dc28dec01558aa 100644 (file)
                        <description>@text/config.inputLabelMulti.description</description>
                </parameter>
        </config-description>
+
 </config-description:config-descriptions>
index 5c453bb2f95ce37572b3ba104cb4dc501b95e326..ae086f42882c91000e27a5706ac30cf24640b35e 100644 (file)
@@ -110,6 +110,14 @@ channel-type.rotel.treble.label = Treble Adjustment
 channel-type.rotel.treble.description = Adjust the treble
 channel-type.rotel.volumeUpDown.label = Volume
 channel-type.rotel.volumeUpDown.description = Increase or decrease the volume
+channel-type.rotel.tcbypass.label = Tone Control Bypass
+channel-type.rotel.tcbypass.description = The user's bass-/treble-settings are bypassed
+channel-type.rotel.balance.label = Balance Adjustment
+channel-type.rotel.balance.description = Adjust the speakers left-right balance
+channel-type.rotel.speakera.label = Speaker-A Adjustment
+channel-type.rotel.speakera.description = Turn on/off the speaker group A
+channel-type.rotel.speakerb.label = Speaker-B Adjustment
+channel-type.rotel.speakerb.description = Turn on/off the speaker group B
 
 # thing type configuration
 
index 824261a7c524822b62425d0a159c38a301ff647f..7a8a74216e5917181f01abfbe976a875b350f8a8 100644 (file)
                        <channel id="bass" typeId="bass"/>
                        <channel id="treble" typeId="treble"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <properties>
index a8aec80d67082bef40773e0f50308de85f4ceaa3..ba667de6411f1d381e3fe8c95bd7c43c57dbe6f6 100644 (file)
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <properties>
index e69b811108b3e4c5ef612a7e8dab42e8bd956102..23a41ad3924f35b25e24ae3885b09f37cd04df02 100644 (file)
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <properties>
index 79c7144463a4f900827a6dcd4e826174948313a3..261e3d9f68c4fced97f37f076815fd7a8064ac16 100644 (file)
                <description>The backlight brightness level (in %) of the device front panel</description>
        </channel-type>
 
+       <channel-type id="tcbypass" advanced="true">
+               <item-type>Switch</item-type>
+               <label>Tone Control Bypass</label>
+               <description>The user's bass-/treble-settings are bypassed</description>
+       </channel-type>
+
+       <channel-type id="balance" advanced="true">
+               <item-type>Number</item-type>
+               <label>Balance Adjustment</label>
+               <description>Adjust the speakers left-right balance</description>
+       </channel-type>
+
+       <channel-type id="speakera" advanced="true">
+               <item-type>Switch</item-type>
+               <label>Speaker-A Adjustment</label>
+               <description>Turn on/off the speaker group A</description>
+       </channel-type>
+
+       <channel-type id="speakerb" advanced="true">
+               <item-type>Switch</item-type>
+               <label>Speaker-B Adjustment</label>
+               <description>Turn on/off the speaker group B</description>
+       </channel-type>
 </thing:thing-descriptions>
index b2480d37d2f2803c46e8cac95c36b21e316ad89c..0ff59b1e9eb4553e5abe16f07081fc59a9b756ab 100644 (file)
@@ -19,6 +19,8 @@
                        <channel id="playControl" typeId="system.media-control"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
                </channels>
 
                <properties>
index 8435e3fe5a09aeac12a9868a66b66ab3304f5504..0330c19d29d1e67c10133dc60bffe8b503c15eb1 100644 (file)
@@ -19,6 +19,8 @@
                        <channel id="playControl" typeId="system.media-control"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
                </channels>
 
                <properties>
index 636b985fa36b67fabf9c673302ac7ea317c185ab..dd38072af3ed7b1b0634956914b7fec142fd45d6 100644 (file)
                        <channel id="playControl" typeId="system.media-control"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <properties>
index d3e671a71ad0b3a5eac5e1b8d6d1c387717a7bc9..8bfbf0730843b411805fb3e28fc967f64565394a 100644 (file)
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>
index 437fd88619cce9df8db8c20263e4574a5bc483b1..bb431ee2af76e0191b1435beeb3b3f786ea218d8 100644 (file)
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
+                       <channel id="speakera" typeId="speakera"/>
+                       <channel id="speakerb" typeId="speakerb"/>
                </channels>
 
                <config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>
index b28f8f33e8f3f2c7e63f2806b609726d77c0db08..449f6d61241fa5e697f978dd4eef116fb48c4ffe 100644 (file)
@@ -19,6 +19,8 @@
                        <channel id="playControl" typeId="system.media-control"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
                </channels>
 
                <properties>
index 0fb3417f38e885969b609e9660c59549eb754562..09e66055a040d9f49081d4cbb60921f9d3609c03 100644 (file)
@@ -18,6 +18,8 @@
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
                </channels>
 
                <config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>
index 86930aa91cda078875e0fd79579ca4ce69345f4b..75c24867f26bab4e99308879367d9205d3e46dc2 100644 (file)
@@ -18,6 +18,8 @@
                        <channel id="treble" typeId="treble"/>
                        <channel id="frequency" typeId="frequency"/>
                        <channel id="brightness" typeId="brightness"/>
+                       <channel id="tcbypass" typeId="tcbypass"/>
+                       <channel id="balance" typeId="balance"/>
                </channels>
 
                <config-description-ref uri="thing-type:rotel:serialandipandprotocol"/>